Zephyr: разработка приложения Печать
Добавил(а) microsin   

В описании этого документа (перевод документации [1]) предполагается, что директория вашего приложения $HOME/app, и директория сборки $HOME/app/build (назначение этих терминов разъясняется далее в секции "Обзор"). На Linux и macOS папка $HOME эквивалентна ~, на Windows это значение переменной окружения %userprofile%.

Система сборки Zephyr основана на CMake.

Система сборки центрична по отношению к приложению, и требует для приложений, основанных на Zephyr, инициацию сборки дерева исходного кода ядра. Сборка приложения управляет конфигурацией и процессом сборки как приложения, так и самой библиотеки Zephyr, компилируя все единый двоичный файл.

Базовый каталог Zephyr содержит собственный исходный код Zephyr, её опции конфигурации ядра и определения для её сборки.

Файлы в директории приложения линкуют Zephyr с приложением. Этот каталог содержит файлы, специфичные для приложения, такие как опции конфигурации и исходный код приложения. В результате приложение имеет простейшую форму, со следующим содержимым:

$HOME/app            (1)
├── CMakeLists.txt   (2)
├── prj.conf         (3)
└── src
    └── main.c       (4)

Здесь представлено следующее:

(1) Корневая папка проекта: это каталог, где находятся все файлы проекта, кроме результатов сборки и временных файлов. Каталог проекта может находиться в любом месте на диске. Обычная практика начать разработку приложения - сделать копию каталога какого-нибудь примера (например из каталога $HOME/zephyrprj/zephyr/samples/).
(2) CMakeLists.txt: этот файл указывает системе сборки, где найти другие файлы приложения, и связывает директорию приложения с системой сборки Zephyr CMake. Эта связь предоставляет для приложения функции системы сборки Zephyr, такие как относящиеся к плате разработчика файлы конфигурации ядра, возможность запуска и к отладки скомпилированных бинарников на реальном или скомпилированном железе, и другие возможности.
(3) Файлы конфигурации ядра: приложение предоставляет файл конфигурации Kconfig (который обычно называется prj.conf). В нем указаны значения, специфичные для приложения, определяющие одну или большее количество опций конфигурации ядра. Эти настройки приложения объединяются с настройками, относящимися к плате, чтобы получить конфигурацию ядра. Для дополнительной информации см. далее "Конфигурация Kconfig".
(4) Файлы исходного кода приложения: приложение обычно состоит из одного или большего количества файлов приложения, написанных на языке C или ассемблера. Эти файлы обычно находятся в подкаталоге src.

Когда приложение определено, Вы можете использовать CMake для создания файлов проекта, чтобы собрать их в директории, которую Вы назначили. Эта директория известна как папка build. Артефакты сборки приложения всегда генерируются в директории build, Zephyr не поддерживает каталоги сборки, находящиеся в локальной папке проекта. Таким образом, временные и выходные файлы всегда находятся в каталоге наподобие $HOME/zephyrprj/build/, независимо от того, какой проект Вы компилируете, и где находится корневая папка проекта.

В последующих секциях описывается создание, сборка и запуск приложений Zephyr, за которым идет более подробное руководство.

[Типы приложений]

На основе того, где находится исходный код приложения, их можно классифицировать на 3 базовые типа.

● Приложения репозитория Zephyr.
● Приложения рабочего пространства Zephyr (workspace-приложения).
● Отдельные приложения Zephyr.

Дополнительную информацию о том, как система сборки поддерживает все типы приложений, описанные в этой секции, см. в статье с описанием пакета Zephyr CMake [4].

Приложения репозитория Zephyr. Приложения, находящиеся в папке zephyr из рабочего пространства Zephyr west, относятся к приложениям репозитория Zephyr. В следующем примере показан проект приложения hello_world из репозитория Zephyr:

zephyrproject/
├─── .west/
│    └─── config
└─── zephyr/
     ├── arch/
     ├── boards/
     ├── cmake/
     ├── samples/
     │    ├── hello_world/
     │    └── ...
     ├── tests/
     └── ...

Приложения рабочего пространства Zephyr. Приложение, находящееся в рабочем пространстве [5], но не в репозитории Zephyr, называется приложением Zephyr workspace. В следующем примере показано такое приложение app:

zephyrproject/
├─── .west/
│    └─── config
├─── zephyr/
├─── bootloader/
├─── modules/
├─── tools/
├─── < vendor/private-repositories>/
└─── applications/
     └── app/

Отдельные приложения Zephyr. К этим приложениям относятся приложения, которые не находятся в произвольном месте на диске, но вне Zephyr workspace и вне репозитория Zephyr. В следующем примере показано отдельное приложение app:

$HOME/
├─── zephyrproject/
│     ├─── .west/
│     │    └─── config
│     ├── zephyr/
│     ├── bootloader/
│     ├── modules/
│     └── ...

└─── app/
     ├── CMakeLists.txt
     ├── prj.conf
     └── src/
         └── main.c

Эталонное workspace-приложение, которое находится в его собственном репозитории Git, можно найти в репозитории Example Application [6]. Его можно использовать как справочник для руководства, как структурировать отдельные рабочие пространства Zephyr, используя топологию T2 star [5]. Также здесь демонстрируется отдельное использование таких функций приложения, как:

● Пользовательские платы.
● Пользовательские объединения дерева устройств.
● Пользовательские драйверы.
● Настройка непрерывной интеграции (Continuous Integration, CI).
● Пример расширения команд west (west extension [7]).

[Создание приложения]

Следуйте этим шагам для создания нового каталога приложения (см. репозиторий Example Application [6] как справочный образец отдельного приложения с собственным репозиторием, или папки Samples и Demos, где находятся готовые примеры приложений, предоставляемых как часть Zephyr). В примере в качестве имени каталога для приложения будет использоваться app.

1. Создайте директорию приложения на своей рабочей станции, вне базовой директории Zephyr. Обычно это папка где-нибудь в домашнем каталоге пользователя (что-то наподобие ~/app, или $HOME/MyProjects/app).

Например, в Unix-шелл или приглашении командной строки Windows cmd.exe командой cd перейдите в каталог, где хотите создать каталог приложения, и введите команду:

mkdir app

Предупреждение: Zephyr не поддерживает сборку или создание приложений в директории, где в имени содержатся пробелы. Таким образом путь до Windows-каталога проекта C:\Users\YourName\app будет допустимым, но путь C:\Users\Your Name\app работать не будет.

2. Рекомендуется помещать весь код приложения в подкаталоге src. Это упрощает разделение файлов проекта и файлов исходного кода. Продолжая наш пример, введите команды:

cd app
mkdir src

3. Поместите исходный код вашего приложения в подкаталог src. Для этого примера предположим, что у нас есть созданный файл исходного кода приложения src/main.c.

4. Создайте файл CMakeLists.txt в директории app со следующим содержимым:

cmake_minimum_required(VERSION 3.20.0) 
 
find_package(Zephyr)
project(my_zephyr_app) 
 
target_sources(app PRIVATE src/main.c)

cmake_minimum_required() требуется для CMake. Он также используется пакетом Zephyr. Использоваться CMake будет самая свежая из двух версий.

find_package(Zephyr) использует систему сборки Zephyr, которая создает CMake target с именем app (см. [4]). Добавление исходников к этому target - способ включить их код в сборку проекта. Пакет Zephyr определит Zephyr-Kernel как CMake-проект, и разрешит поддержку языков C, CXX, ASM.

project(my_zephyr_app) требуется для определения вашего проекта приложения. Это должно быть вызвано после find_package(Zephyr), чтобы избежать конфликта с проектом Zephyr (Zephyr-Kernel).

target_sources(app PRIVATE src/main.c) добавление файла исходного кода к app target. Эта строчка должна находится после строки find_package(Zephyr), которая определяет target.

5. Установите опции конфигурации, см. далее "Конфигурация Kconfig".

6. Сконфигурируйте любые оверлеи дерева устройств, необходимые приложению (см. [8]).

Примечание: для обеспечения обратной совместимости со старыми приложениями все еще поддерживается include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE). Подключение boilerplate.cmake напрямую непосредственно в пример все еще требует использования Zephyr Environment Scripts перед сборкой приложения.

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

Замечание: переменные BOARD, CONF_FILE и DTC_OVERLAY_FILE могут быть предоставлены для системы сборки тремя способами (в порядке предпочтения):

● В качестве параметров для west build, или вовлечения cmake через ключ командной строки -D. Если у вас есть несколько файлов оверлея, то необходимо использовать кавычки, "file1.overlay;file2.overlay".
● Через переменные окружения.
● Путем установки оператора (< VARIABLE> < VALUE>) в вашем файле CMakeLists.txt.

ZEPHYR_BASE: базовая переменная Zephyr, используемая системой сборки. Вызов find_package(Zephyr) автоматически установит её значение как кэшируемой переменной CMake. Однако ZEPHYR_BASE может также быть установлена как переменная окружения, чтобы принудительно заставить CMake использовать определенную инсталляцию Zephyr.

BOARD: выбирает плату, которую сборка приложения будет использовать в качестве конфигурации по умолчанию. См. список поддерживаемых плат [9], и руководство по портированию [10] для получения информации по добавлению поддержки платы.

CONF_FILE: показывает имя файла для одного или большего количества файлов фрагмента конфигурации Kconfig. Несколько имен файлов могут отделяться друг от друга либо пробелами, либо точкой с запятой. Каждый файл включает значения конфигурации Kconfig, которые переназначают значения конфигурации по умолчанию. Для дополнительной информации см. раздел "Initial Configuration" документации [11].

OVERLAY_CONFIG: дополнительные файлы фрагмента конфигурации Kconfig. Несколько имен файлов могут отделяться друг от друга либо пробелами, либо точкой с запятой. Это может быть полезно, чтобы оставить значение по умолчанию CONF_FILE, но при этом "подмешать" некоторые дополнительные опции конфигурации.

DTC_OVERLAY_FILE: один или несколько используемых файлов оверлея. Несколько файлов могут быть отделены друг от друга точкой с запятой. Для примера см. раздел "Set devicetree overlays" документации [8], а также см. [12] для описания devicetree и Zephyr.

SHIELD: см. описание дочерних плат [13].

ZEPHYR_MODULES: список CMake содержит абсолютные пути дополнительных директорий с исходным кодом, Kconfig, и т. п., которые должны использоваться в сборке приложения. Для дополнительной информации см. [14]. Если Вы установите эту переменную, то это должен быть полный список используемых модулей, поскольку система сборки не будет автоматически брать любые модули из west.

ZEPHYR_EXTRA_MODULES: работает наподобие ZEPHYR_MODULES, за исключением того, что вместо замены модулей west они будут добавлены к списку модулей west.

Примечание: вы можете использовать пакет Zephyr Build Configuration CMake для совместного использования настроек для этих переменных.

[Файл CMakeLists.txt приложения]

В каждом приложении должен быть файл CMakeLists.txt. Этот файл является точкой входа, или верхним уровнем для системы сборки. Конечный образ zephyr.elf содержит как приложение, так и библиотеки ядра.

В этой секции описано кое-что, что вы можете делать со своим CMakeLists.txt. Убедитесь, что выполняете все действия в следующем порядке.

1. Если Вы хотите выполнить сборку для одной платы, то добавьте имя конфигурации платы для своего приложения в новую строку (информацию по поддерживаемым платам см. в [9]). Например:

set(BOARD qemu_x86)

Система сборки Zephyr определит значение для BOARD путем проверки следующих источников, в таком порядке (когда значение BOARD найдено, CMake прекращает просмотр этого списка):

● Наивысший приоритет имеет используемое ранее значение, как определено в кэше CMake. Это даст гарантию, что не будет попытки запустить сборку с другим значением BOARD, отличающимся от установки, сделанной на шаге конфигурации сборки.
● Любое значение, указанное непосредственно в командной строке command (либо напрямую, либо косвенно через west build), используя -DBOARD=YOUR_BOARD.
● Если установлена переменная окружения BOARD, то будет использовано это значение.
● И наконец, если Вы установили BOARD в своем CMakeLists.txt приложения, как описано в этом шаге.

2. Если ваше приложение использует конфигурационный файл или файлы, отличающиеся от обычного prj.conf (или prj_YOUR_BOARD.conf, где YOUR_BOARD это название платы), то соответственно добавьте строки настройки переменной CONF_FILE в эти файлы. Если имеется несколько файлов, то отделяйте их имена друг от друга точкой с запятой. Могут использоваться списки CMake, чтобы составить файлы фрагментов конфигурации по модульному принципу, когда Вы хотите избежать установки CONF_FILE в одном месте. Например:

set(CONF_FILE "fragment_file1.conf")
list(APPEND CONF_FILE "fragment_file2.conf")

Для дополнительной информации см. раздел "Initial Configuration" статьи [11].

3. Если приложение использует оверлеи devicetree, то может понадобиться установить DTC_OVERLAY_FILE [8].

4. Если у вашего приложения собственные опции конфигурации ядра, то создайте файл Kconfig в той же директории, что и файл CMakeLists.txt приложения. Также см. секцию Kconfig руководства [3].

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

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

Структура вашего файла Kconfig примерно такая:

# SPDX-License-Identifier: Apache-2.0
 
mainmenu "Your Application Name"
 
# Создайте здесь опции конфигурации вашего приложения.
 
# Исходники Kconfig.zephyr находятся к корневой директории Zephyr.
#
# Примечание: все операторы 'source' работают относительно корневой директории
# Zephyr (из-за переменной окружения $srctree, установленной в $ZEPHYR_BASE).
# Если вы хотите вместо этого сделать 'source' относительно текущего файла
# Kconfig, то используйте 'rsource' (или путь относительнo корня Zephyr).
source "Kconfig.zephyr"

Примечание: переменные окружения в операторах source расширяются напрямую, так что нет необходимости определять опцию env="ZEPHYR_BASE" для символа Kconfig "bounce". Если вы используете такой символ, то он должен иметь такое же имя как переменная окружения. Для дополнительной информации см. [15].

Файл Kconfig определяется автоматически, когда он помещен в директорию приложения, но он может быть также найден где-нибудь в другом месте, если CMake-переменная окружения KCONFIG_ROOT установлена в абсолютный путь.

5. Укажите, что приложение требует Zephyr на новой строке, после любых строк, добавленных на шагах, описанных выше:

find_package(Zephyr)
project(my_zephyr_app)

Примечание: может использоваться find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}), если нужно взять определенную инсталляцию Zephyr путем явной установкой переменной окружения ZEPHYR_BASE. Все примеры в Zephyr поддерживают переменную окружения ZEPHYR_BASE.

6. Теперь добавьте любые файлы приложения с исходным кодом в target-библиотеку 'app', каждый в отдельной строке, примерно так:

target_sources(app PRIVATE src/main.c)

Ниже показан простой пример CMakeList.txt:

set(BOARD qemu_x86)
 
find_package(Zephyr)
project(my_zephyr_app)
 
target_sources(app PRIVATE src/main.c)

Cmake-свойство HEX_FILES_TO_MERGE усиливает конфигурацию приложения, предоставленную Kconfig и CMake, чтобы позволить вам склеить собранные внешне hex-файлы с hex-файлом, сгенерированным при сборке приложения Zephyr. Например:

set_property(GLOBAL APPEND PROPERTY HEX_FILES_TO_MERGE
    ${app_bootloader_hex}
    ${PROJECT_BINARY_DIR}/${KERNEL_HEX_NAME}
    ${app_provision_hex})

[CMakeCache.txt]

CMake использует файл CMakeCache.txt как постоянное хранилище пар строк key/value, используемое для кэширования значений между запусками сборки, включая опции компиляции и сборки, и пути до библиотечных зависимостей. Этот файл кэша создается, когда CMake запускается в пустой папке build.

Для дополнительной информации про файл CMakeCache.txt см. официальную документацию по запуску CMake [16] documentation runningcmake

[Конфигурация приложения]

Директория конфигурации. Zephyr будет использовать файлы конфигурации из директории конфигурации приложения, за исключением файлов по абсолютному пути, предоставленному описанными выше аргументами, например CONF_FILE, OVERLAY_CONFIG и DTC_OVERLAY_FILE.

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

1. Если задана переменная APPLICATION_CONFIG_DIR через опцию -DAPPLICATION_CONFIG_DIR=< путь> или в файле CMake перед find_package(Zephyr), то эта папка используется как директория конфигурации приложения.

2. Директория исходного кода приложения.

Конфигурация Kconfig. Опции конфигурации приложения обычно установлены в файле prj.conf, находящемся директории приложения. Например, поддержка C++ должна быть разрешена следующим назначением:

CONFIG_CPLUSPLUS=y

Просмотр существующих примеров - хорошая точка для начального старта.

В документации [11] подробно описывается установка значений конфигурации Kconfig. В секции "Initial Configuration" этой документации показано, как вычисляется начальная конфигурация. См. "Kconfig Search" для получения полного списка опций конфигурации. См. [17] для информации безопасности, связанной с опциями Kconfig.

Другие страницы руководства [18] также заслуживают внимания, особенно если вы планируете добавить новые опции конфигурации.

[Экспериментальные функции]

Zephyr это проект, который находится в постоянной разработке, и поэтому существуют функции, которые все еще находятся на ранней стадии разработки. Такие функции будут помечены [EXPERIMENTAL] в их заголовке Kconfig.

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

CONFIG_WARN_EXPERIMENTAL=y

Например, если опция CONFIG_FOO является экспериментальной, то разрешение её и разрешение опции CONFIG_WARN_EXPERIMENTAL приведет к выводу следующего предупреждения на этапе конфигурирования CMake, когда происходит сборка приложения:

warning: Experimental symbol FOO is enabled.

[Код, специфичный для приложения]

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

Код приложения не должен использовать имена символов с префиксами, зарезервированными для использования ядром. Для дополнительной информации см. описание соглашений об именовании символов [19].

Код библиотек сторонних разработчиков. Есть возможность собрать код библиотеки вне директории приложения src, однако важно соблюдать условие, чтобы двоичный интерфейс приложения (Application Binary Interface, ABI) целевого процессора (target) был один и тот же и для приложения, и для библиотеки. На большинстве архитектур существуют флаги компилятора, которыми управляет целевой ABI, поэтому важно, чтобы и у библиотек, и у приложений были одинаковые (общие) определенные флаги компилятора. Также может быть полезным, чтобы приклеиваемый код имел доступ к заголовочным файлам ядра Zephyr.

Чтобы упростить интеграцию сторонних компонент кода, у системы сборки Zephyr есть определения функций CMake, которые дают скриптам сборки приложения доступ к опциям компиляции Zephyr. Эти функции документированы и определены в cmake/extensions.cmake, и придерживаются соглашения именования zephyr_get_< type>_< format>.

Сторонней системе сборки часто нужно предоставить следующие переменные.

CMAKE_C_COMPILER, CMAKE_AR.
ARCH и BOARD, вместе с некоторыми переменными, которые идентифицируют версию ядра Zephyr.

Проект samples/application_development/external_lib демонстрирует некоторые из этих функций.

[Сборка приложения]

Система сборки Zephyr компилирует и связывает все компоненты приложения в один образ приложения, который может быть запущен на симулированном или реальном железе.

Как в любой другой основанной на CMake системе, процесс сборки состоит из 2 стадий [20]. Сначала генерируются файлы сборки (также известные как buildsystem) с помощью командной строки cmake, которая задает генератор. Этот генератор определяет традиционный инструментарий сборки (компилятор/линковщик), который buildsystem будет использовать на второй стадии. На второй стадии запускается инструментарий сборки, который реально выполняет компиляцию и сборку исходных файлов, с генерацией образа исполняемого кода. Более подробно про эту концепцию см. "CMake introduction" в официальной документации CMake.

Хотя инструментарием сборки по умолчанию в Zephyr является west (Zephyr meta-tool), который запускает за сценой cmake и нижележащий инструментарий сборки (ninja или make), вы также можете, если пожелаете, запускать cmake напрямую. На Linux и macOS вы можете выбрать между генераторами make и ninja (например инструментарий сборки), в то время как на Windows вам нужно использовать ninja, поскольку на этой платформе make не поддерживается. В этом руководстве для упрощения будет использоваться ninja, и если вы выбрали использование west build для сборки приложения, то знайте, что под капотом по умолчанию будет запускаться ninja.

В качестве примера давайте соберем Hello World для reel_board. При использовании west:

west build -b reel_board samples/hello_world

При использовании CMake и ninja:

# Для конфигурирования buildsystem на основе Ninja используется cmake:
cmake -Bbuild -GNinja -DBOARD=reel_board samples/hello_world
 
# Теперь запустим ninja на сгенерированной buildsystem:
ninja -Cbuild

На Linux и macOS можно также сделать сборку с make вместо ninja. При использовании west:

● Для однократного использования make добавьте -- -G"Unix Makefiles" к командной строке west. Для примера см. документацию west build [22].
● Теперь для использования по умолчанию make, запустите west config build.generator "Unix Makefiles".

При использовании CMake напрямую:

# Для конфигурирования buildsystem на основе Ninja используется cmake:
cmake -Bbuild -DBOARD=reel_board samples/hello_world
 
# Теперь запустим ninja на сгенерированной buildsystem:
make -Cbuild

Основы. В примере ниже west используется вне своего рабочего пространства (west workspace). Чтобы это работало, вы должны использовать переменную окружения ZEPHYR_BASE, чтобы указать путь до вашего репозитория zephyr git, с использованием одного из методов на страничке с описанием переменных окружения Zephyr [23].

Перейдите в директорию приложения $HOME/app. Введите следующие команды для сборки образа приложения zephyr.elf для платы board, указанной в параметрах командной строки. С использованием west:

west build -b < board>

С использованием CMake и ninja:

mkdir build && cd build
 
# Для конфигурирования buildsystem на основе Ninja используется cmake:
cmake -GNinja -DBOARD=< board> ..
 
# Запуск ninja на сгенерированной buildsystem:
ninja

Если хотите, вы можете собрать приложение с настройками конфигурации, указанными в альтернативном .conf-файле, используя параметр CONF_FILE. Эти настройки переназначат настройки в файле .config приложения, или в его дефолтном файле .conf.

Например, с использованием west:

west build -b < board> -- -DCONF_FILE=prj.alternate.conf

С использованием CMake и ninja:

mkdir build && cd build
cmake -GNinja -DBOARD=< board> -DCONF_FILE=prj.alternate.conf ..
ninja

Как было описано в предыдущей секции, вы можете выбрать вместо этого постоянно заданные настройки платы и конфигурации либо экспортированием переменных окружения BOARD и CONF_FILE, либо установкой их значений в CMakeLists.txt операторами set(). Дополнительно west позволяет вам установить плату по умолчанию (см. build.board в документации [22]).

Содержимое директории build. Когда используется генератор Ninja, директория build выглядит примерно так:

$HOME/app/build
├── build.ninja
├── CMakeCache.txt
├── CMakeFiles
├── cmake_install.cmake
├── rules.ninja
└── zephyr

Наиболее значимые файлы в этой директории:

build.ninja, этот файл может использоваться для сборки приложения.

● Подкаталог zephyr, рабочая директория для генерируемой buildsystem, в эту директорию сохраняются большинство генерируемых файлов.

После запуска ninja в подкаталог zephyr будут записаны следующие выходные файлы (это не базовая директория Zephyr, где содержится исходный код Zephyr, как было описано выше).

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

Примечание: предыдущая версия .config сохраняется в .config.old всякий раз, когда обновляется конфигурация. Это сделано для удобства, поскольку может быть полезным сравнение старой и новой версии конфигурации.

● Различные объектные файлы (с расширениями .o и .a), где содержится скомпилированный код ядра и приложения.

zephyr.elf, который содержит конечный двоичный код скомбинированных друг с другом приложения и ядра. Также поддерживаются другие двоичные выходные форматы, такие как .hex и .bin.

Повторная сборка приложения. Разработка приложения обычно происходит быстрее, когда изменения постоянно проверяются. Частые пересборки приложения делают отладку менее болезненной, поскольку приложение усложняется постепенно, и есть возможность отследить момент появления ошибки. Чаще всего хорошей идеей будет пересобрать и проверить приложение после любых значимых изменений в файлах исходного кода приложения, файлах CMakeLists.txt, или в настройках конфигурации.

Важное замечание: система сборки Zephyr пересобирает только те части образа приложения, которые потенциально были подвержены изменениям. Как следствие пересборка происходит значительно быстрее, чем первая сборка с нуля (или сборка после команды очистки clean, или после удаления каталога build).

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

1. Откройте консоль терминала команд и перейдите в директорию $HOME/app/build.

2. Введите одну из следующих команд в зависимости от того, что хотите использовать - west или напрямую cmake - чтобы удалить сгенерированные файлы приложения, кроме файла .config, который содержит текущую информацию конфигурации приложения:

west build -t clean

или:

ninja clean

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

west build -t pristine

или:

ninja pristine

Если вы используете west, то можете воспользоваться его преимуществом автоматического создания подкаталога build всякий раз, когда это необходимо [22].

3. Ребилд приложения обычно выполняется шагами, указанными выше в разделе "Сборка приложения".

Сборка для ревизии платы. Система сборки Zephyr обладает поддержкой нескольких ревизий аппаратуры одной платы, когда у ревизий есть незначительные отличия. Использование ревизий позволяет делать минимальные подстройки файлов поддержки платы и избежать дублирования для каждой ревизии всех файлов, описанных в секции "Create your board directory" документации по портированию [10].

Чтобы выполнить сборку для определенной ревизии платы, используйте команду < board>@< revision> вместо < board>. Например, с использованием west:

west build -b < board>@< revision>

С использованием CMake и ninja:

mkdir build && cd build
cmake -GNinja -DBOARD=< board>@< revision> ..
ninja

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

Когда делается сборка на целевую ревизию платы, активная ревизия будет выведена во время конфигурирования CMake, примерно так:

-- Board: plank, Revision: 1.5.0

[Запуск приложения]

Скомпилированный образ приложения можно запустить на реальной плате или на эмулированном железе.

Запуск на плате. Большинство плат, поддерживаемых Zephyr, позволяют выполнить прошивку скомпилированного бинарника командой flash. Эта команда прошьет код приложения в плату и запустит его на выполнение. Чтобы запустить приложение на реальном железе, выполните следующие действия.

1. Выполните сборку приложения, как это было описано выше в секции "Сборка приложения".

2. Убедитесь, что плата подключена к хосту разработки. Обычно подключение осуществляется через USB.

3. Запустите одну из этих команд из директории сборки $HOME/app/build, чтобы прошить скомпилированный образ Zephyr и запустить его на вашей плате:

west flash

или:

ninja flash

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

Каждый раз, когда вы запускаете команду flash, ваше приложение пересобирается и заново прошивается (подобным образом устроена система сборки ESP-IDF).

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

Примечание: когда происходит разработка на хосте Linux, обычно необходимо инсталлировать правила udev, специфические для платы, чтобы был разрешен доступ к устройству USB платы для пользователя, не обладающего правами root. Если прошивка не получается, проконсультируйтесь с документацией на плату, необходима ли установка дополнительных разрешений доступа к ней.

Запуск на эмуляторе. У ядра есть встроенная поддержка эмулятора для QEMU (работает только на Linux/macOS, в настоящий момент на Windows не поддерживается). Это дает возможность виртуального запуска и тестирования приложения, перед загрузкой (или вместо неё) образа в реальное железо. Для запуска приложения через QEMU выполните следующие действия:

1. Выполните сборку своего приложения для одной из плат QEMU, как это было описано выше в секции "Сборка приложения". Например, можно установить BOARD в следующие значения:

qemu_x86 для эмуляции запуска кода на плате, основанной на процессоре x86.
qemu_cortex_m3 для эмуляции запуска кода на плате, основанной на процессоре ARM Cortex M3.

2. Запустите одну из следующих команд консоли из директории сборки $HOME/app/build, чтобы запустить бинарник Zephyr в QEMU:

west build -t run

или:

ninja run

Для остановки работы приложения, работающего в QEMU, нажмите комбинацию клавиш Ctrl+A+X. Приложение остановит свою работу, и появится приглашение ввода команды консоли.

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

Примечание: если (относится только к Linux) установлен Zephyr SDK, то по умолчанию run будет использовать бинарник QEMU из SDK. Для использования другой версии QEMU, установите переменную окружения QEMU_BIN_PATH в значение пути до бинарника QEMU, который хотите использовать вместо бинарника QEMU по умолчанию.

Можно использовать определенный эмулятор для QEMU путем добавления _< emulator> к имени вашей target, например west build -t run_qemu или ninja run_qemu.

[Отладка приложения]

В этой секции приведено краткое руководство для запуска отладки приложения QEMU. Большинство содержимого в этой секции также описано в документации эмулятора QEMU [24] и отладчика GNU [25]. В этой секции описываются горячие клавиши, специальные переменные окружения и параметры, которые могут помочь быстро настроить рабочее окружение отладки.

Самый простой способ отладки приложения, запущенного в QEMU - использование GNU Debugger и установка локального сервера GDB в системе разработки через QEMU.

Для отладки вам понадобится двоичный образ исполняемого кода в формате Executable and Linkable Format (ELF). Система сборки генерирует этот образ в директории build. По умолчанию имя образа zephyr.elf. Это имя может быть изменено опцией Kconfig.

Мы будем использовать стандартный порт 1234 TCP для запуска экземпляра сервера GDB. Этот номер порта может быть изменен на другое значение, которое больше подходит для вашего окружения разработки.

Вы можете запустить QEMU для прослушивания "gdb connection" перед запуском любого кода с целью отладки. Следующая команда настроит Qemu для прослушивания порта по умолчанию 1234 и ожидания подключения к нему отладчика GDB.

qemu -s -S < image>

Используемые здесь опции имеют следующий смысл:

-S не запускать CPU на startup; вместо этого вам надо ввести в мониторе 'c'.
-s сокращение для -gdb tcp::1234, что откроет GDB на порту TCP 1234.

Для отладки вместе с QEMU и запуска сервера GDB с ожиданием сетевого соединения, в директории build приложения запустите одно из следующих действий:

ninja debugserver

Система сборки запустит экземпляр QEMU с CPU, приостановленном на startup, и с экземпляром сервера GDB, прослушивающим порт TCP 1234.

Использование локальной GDB-конфигурации .gdbinit может помочь инициализировать ваш экземпляр GDB при каждом запуске. В этом примере файл инициализации указывает на экземпляр сервера GDB. Это сконфигурирует соединение с сетевым remote на локальном хосте, через порт TCP 1234. Инициализация установит корневой каталог ядра в качестве привязки.

Файл .gdbinit содержит следующие строки (замените ZEPHYR_BASE на корректный путь для вашей системы):

target remote localhost:1234
dir ZEPHYR_BASE

Запустите приложение для отладки из той же директории, которую выбрали для файла gdbinit. Команда может включать опцию --tui для разрешения использования терминала в качестве интерфейса с пользователем. Следующие команды выполнят подключение к серверу GDB с помощью gdb. Команда загрузит таблицу символов из двоичного elf-файла, например:

..../путь/до/gdb --tui zephyr.elf

Примечание: версия GDB на системе отладки может не поддерживать опцию –tui. Убедитесь, что используете бинарник GDB из SDK, который соответствует тулчейну, использовавшегося для сборки двоичного кода приложения.

Если файл .gdbinit не используется, то выдайте следующую команду внутри GDB для подключения к серверу GDB через порт 1234:

(gdb) target remote localhost:1234

И наконец, следующая команда соединит сервер GDB с помощью Data Displayer Debugger (ddd). Команда загрузит таблицу символов из двоичного elf-файла, в этом примере zephyr.elf.

По умолчанию DDD может быть не установлен в вашей системе разработки. Следуйте инструкциями вашей системы для его установки, например используйте sudo apt-get install ddd на системе Ubuntu.

ddd --gdb --debugger "gdb zephyr.elf"

Обе команды запустят gdb. Имя команды может поменяться в зависимости от используемого вами тулчейна и кроссплатформенного инструментария.

[Пользовательские платы, Devicetree и определения SOC]

В случаях, когда плата или платформа, на которых вы разрабатываете приложение, пока не поддерживаются Zephyr, есть возможность добавить плату, Devicetree и определения SOC для приложения без необходимости добавлять их в дерево Zephyr.

Структура добавления для поддержки платы и разработки SOC должна быть подобна той, которая используется для плат и SOC-ов в дереве Zephyr. При использовании этой структуры будет много проще начать работу с вашей платформой в дереве Zephyr после того, как первоначальная разработка будет завершена.

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

boards/
soc/
CMakeLists.txt
prj.conf
README.rst
src/

Здесь директория boards размещает в себе плату, для которой производится сборка:

.
├── boards
│   └── x86
│       └── my_custom_board
│           ├── doc
│           │   └── img
│           └── support
└── src

Директория soc содержит любой код, относящийся к SOC. Можно также иметь платы, которые поддерживаются SOC, доступными в дереве Zephyr.

Платы. Используйте правильное имя папки, соответствующее архитектуре (например x86, arm, и т. п.) в каталоге boards для подкаталога my_custom_board (см. список поддерживаемых плат [9] для информации по архитектурам плат).

Документация (в подкаталоге doc/) и файлы поддержки (в подкаталоге support/) не обязательны, однако понадобятся для предоставления в Zephyr.

Содержимое папки my_custom_board должно соответствовать тем же рекомендациям, которые действуют для всех плат Zephyr, и в этой папке должны быть следующие файлы:

my_custom_board_defconfig
my_custom_board.dts
my_custom_board.yaml
board.cmake
board.h
CMakeLists.txt
doc/
Kconfig.board
Kconfig.defconfig
pinmux.c
support/

Когда структура файлов и каталогов платы создана, можно выполнить сборку вашего приложения с нацеливанием на эту плату, путем указания на место размещения информации вашей платы параметром -DBOARD_ROOT для системы сборки CMake. С использованием west:

west build -b < имя платы> -- -DBOARD_ROOT=< путь до boards>

С использованием CMake и ninja:

cmake -Bbuild -GNinja -DBOARD=< имя платы> -DBOARD_ROOT=< путь до boards> .
ninja -Cbuild

Это будет использовать вашу конфигурацию платы и сгенерирует бинарник Zephyr в директории вашего приложения.

Также вы можете определить переменную BOARD_ROOT в файле CMakeLists.txt приложения. Убедитесь, что это сделано перед тем, как вовлекать шаблон Zephyr с помощью find_package(Zephyr ...).

Примечание: когда в файле CMakeLists.txt указывается BOARD_ROOT, должен быть предоставлен абсолютный пут, например list(APPEND BOARD_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/< extra-board-root>). Когда используется -DBOARD_ROOT=< board-root>, могут использоваться как абсолютные, так и относительные пути. Относительные пути обрабатываются от директории приложения.

Определения SOC. Подобно добавлению поддержки платы, следует придерживаться корректной структуре определения SOC, соответствующей дереву Zephyr, например:

soc
└── arm
    └── st_stm32
            ├── common
            └── stm32l0

Файл soc/Kconfig создаст меню выбора конфигурации верхнего уровня SoC/CPU/Configuration Selection в Kconfig.

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

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

soc
└── arm
    └── st_stm32
            ├── Kconfig
            ├── Kconfig.soc
            └── Kconfig.defconfig

Файлы Kconfig в примере выше могут описывать SoC, или загружать дополнительные файлы SoC Kconfig.

Пример загрузки в эту структуру файлов Kconfig, специфичных для stm31l0:

soc
└── arm
    └── st_stm32
            ├── Kconfig.soc
            └── stm32l0
                └── Kconfig.series

Эта загрузка может быть выполнена со следующим содержимым в st_stm32/Kconfig.soc:

rsource "*/Kconfig.series"

Как только структура SOC создана, вы можете выполнить сборку своего приложения, нацеливаясь на эту платформу, путем указания информации по вашей платформе в параметре -DSOC_ROOT системы сборки CMake. С использованием west:

west build -b < имя платы> -- -DSOC_ROOT=< путь до soc> -DBOARD_ROOT=< путь до boards>

С использованием CMake и ninja:

cmake -Bbuild -GNinja -DBOARD=< имя платы> -DSOC_ROOT=< путь до soc> -DBOARD_ROOT=< путь до boards> .
ninja -Cbuild

Это будет использовать пользовательские конфигурации платформы и сгенерирует бинарник Zephyr в директории вашего приложения.

См. секцию "Build settings" документации [26] для информации по установке SOC_ROOT в файле модуля zephyr/module.yml.

Альтернативно вы можете определить переменную SOC_ROOT в файле CMakeLists.txt приложения. Убедитесь, что это сделано перед тем, как вовлекать шаблон Zephyr с помощью find_package(Zephyr ...).

Примечание: кода указывается SOC_ROOT в CMakeLists.txt, должны предоставляться абсолютные пути, например list(APPEND SOC_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/< extra-soc-root>. Когда используется -DSOC_ROOT=< soc-root>, можно указывать и абсолютные, и относительные пути. Относительные пути обрабатываются от директории приложения.

Определения Devicetree. Деревья директорий Devicetree находятся в APPLICATION_SOURCE_DIR, BOARD_DIR и ZEPHYR_BASE, однако могут быть добавлены дополнительные деревья, или DTS_ROOT, путем создания следующего дерева директорий:

include/
dts/common/
dts/arm/
dts/
dts/bindings/

Здесь 'arm' меняется на подходящую архитектуру. Каждая директория опциональна. Директория binding содержит привязки, и другие директории содержат файлы, которые могут быть подключены из исходного кода DT.

Как только эта структура директорий создана, её можно использовать путем указания места расположения через Cache-переменную DTS_ROOT CMake. С использованием west:

west build -b < имя платы> -- -DDTS_ROOT=< путь до корня dts>

С использованием CMake и ninja:

cmake -Bbuild -GNinja -DBOARD=< имя платы> -DDTS_ROOT=< путь до корня dts> .
ninja -Cbuild

Также вы можете определить переменную DTS_ROOT в файле CMakeLists.txt приложения. Убедитесь, что это сделано перед тем, как вовлекать шаблон Zephyr с помощью find_package(Zephyr ...).

Примечание: когда указываете DTS_ROOT в CMakeLists.txt, должны быть предоставлены абсолютные пути, например list(APPEND DTS_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/< extra-dts-root>. Когда используется -DDTS_ROOT=< dts-root>, могут указаны как абсолютные, так и относительные пути. Относительные пути обрабатываются от директории приложения.

Источник Devicetree проходит через обработку препроцессора C, так что вы можете подключить файлы которые находятся в директории DTS_ROOT. По соглашению подключаемые файлы devicetree имеют расширение .dtsi.

Также можно использовать препроцессор для управления содержимым файла devicetree, путем указания директив через Cache-переменную DTS_EXTRA_CPPFLAGS CMake. С использованием west:

west build -b < имя платы> -- -DDTS_EXTRA_CPPFLAGS=-DTEST_ENABLE_FEATURE

С использованием CMake и ninja:

cmake -Bbuild -GNinja -DBOARD=< имя платы> -DDTS_EXTRA_CPPFLAGS=-DTEST_ENABLE_FEATURE .
ninja -Cbuild

CMake поддерживает генерацию файла описания проекта, который может импортироваться в Eclipse Integrated Development Environment (IDE), и использоваться для отладки с графическим интерфейсом.

Плагины GNU MCU Eclipse предоставляют механизм отладки ARM-проектов в Eclipse с помощью pyOCD, Segger J-Link и инструментария OpenOCD.

Следующее руководство демонстрирует, как отлаживать приложение Zephyr в Eclipse на Windows с помощью pyOCD. Подразумевается, что уже установлены GCC ARM Embedded и pyOCD.

[Настройка окружения разработки Eclipse]

1. Загрузите и установите Eclipse IDE for C/C++ Developers. Можно сразу установить систему разработки ESP_IDF, в интерфейсе GUI которой используется Eclipse [28].

2. В Eclipse установите плагины GNU MCU Eclipse через меню Window -> Eclipse Marketplace..., найдите GNU MCU Eclipse, и кликните Install на результате поиска.

3. Сконфигурируйте путь до сервера pyOCD GDB через меню Window -> Preferences, перейдите к MCU и установите Global pyOCD Path.

[Генерация и импорт проекта Eclipse]

1. Настройте тулчейн GNU Arm Embedded, как это описано в [27].

2. Перейдите в папку вне дерева Zephyr для сборки своего приложения:

cd %userprofile%

Примечание: если директория build это подкаталог директории исходного кода, как обычно принято в Zephyr, то CMake выведет предупреждение: "Директория build является подкаталогом директории source. Это не поддерживается Eclipse. Настоятельно рекомендуется использовать директорию build, которая соседняя с директорией source".

3. Сконфигурируйте свое приложение с помощью CMake, и выполните его сборку с помощью ninja. Имейте в виду, что указывается другой генератор CMake через аргумент -G"Eclipse CDT4 - Ninja". Это сгенерирует файл описания проекта Eclipse .project, в дополнение к обычным файлам сборки ninja.

С использованием west:

west build -b frdm_k64f %ZEPHYR_BASE%\samples\synchronization -- -G"Eclipse CDT4 - Ninja"

С использованием CMake и ninja:

cmake -Bbuild -GNinja -DBOARD=frdm_k64f -G"Eclipse CDT4 - Ninja" %ZEPHYR_BASE%\samples\synchronization
ninja -Cbuild

4. В Eclipse сделайте импорт сгенерированного проекта через меню File -> Import... и выберите опцию Existing Projects into Workspace. Перейдите в директорию build приложения (Select root directory:). Поставьте галочку для своего проекта в списке найденных проектов, и кликните на кнопке Finish.

[Создание конфигурации отладчика]

1. Откройте меню Run -> Debug Configurations...

2. Выберите GDB PyOCD Debugging, кликните на кнопку New и сконфигурируйте следующие опции.

● На закладке Main:

- Project: my_zephyr_app@build
- C/C++ Application: zephyr/zephyr.elf

● На закладке Debugger:

- pyOCD Setup
   Executable path: $pyocd_path\$pyocd_executable
   Снимите галочку "Allocate console for semihosting"

- Board Setup
   Bus speed: 8000000 Hz
   Снимите галочку "Enable semihosting"

- GDB Client Setup

   Пример пути запуска (используйте свой GNUARMEMB_TOOLCHAIN_PATH):
   C:\gcc-arm-none-eabi-6_2017-q2-update\bin\arm-none-eabi-gdb.exe

● На закладке SVD Path:

   File path: < workspace top>\modules\hal\nxp\mcux\devices\MK64F12\MK64F12.xml

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

3. Кликните на кнопку Debug для запуска отладки.

[RTOS]

Поддержка для Zephyr RTOS реализована в pyOCD v0.11.0 и более свежей версии. Эта поддержка совместима с GDB PyOCD Debugging в Eclipse, однако нужно разрешить CONFIG_DEBUG_THREAD_INFO=y в вашем приложении.

[Ссылки]

1. Zephyr Application Development site:zephyrproject.org.
2. Zephyr: быстрый старт.
3. Zephyr: конфигурация Kconfig.
4Zephyr: пакет CMake.
5. Zephyr Workspaces site:zephyrproject.org.
6. zephyrproject-rtos / example-application site:github.com.
7. Zephyr west extensions site:zephyrproject.org.
8. Zephyr Devicetree HOWTOs site:zephyrproject.org.
9. Zephyr Supported Boards site:zephyrproject.org.
10. Zephyr Board Porting Guide site:zephyrproject.org.
11. Zephyr Setting Kconfig configuration values site:zephyrproject.org.
12. Zephyr Introduction to devicetree site:zephyrproject.org.
13. Zephyr Shields site:zephyrproject.org.
14. Zephyr Modules (External projects) site:zephyrproject.org.
15. Zephyr Kconfig extensions site:zephyrproject.org.
16. Running CMake site:cmake.org.
17. Zephyr Hardening Tool site:zephyrproject.org.
18. Zephyr Configuration System (Kconfig) site:zephyrproject.org.
19. Zephyr Naming Conventions site:github.com.
20. Zephyr Build System (CMake) site:zephyrproject.org.
21. Introduction to CMake Buildsystems site:cmake.org.
22. west Building, Flashing and Debugging site:zephyrproject.org.
23. Zephyr Environment Variables site:zephyrproject.org.
24. QEMU Main Page site:wiki.qemu.org.
25. GDB: The GNU Project Debugger site:sourceware.org.
26. Zephyr Modules (External projects) site:zephyrproject.org.
27. Zephyr GNU Arm Embedded site:zephyrproject.org.
28Установка среды разработки ESP-IDF для ESP32.