こんにちは!Zephyr OS入門シリーズの実践編です。
これまでの連載で、Zephyr OSの基本概念(マルチスレッド、IPC、DeviceTree/Kconfig)について解説してきました。
今回は、実際に自分でプロジェクトを立ち上げて開発を進めるために不可欠な「Zephyr本体と自作アプリを含めた全体のフォルダ階層構造」と、「各種設定ファイル(CMakeLists.txt / prj.conf / app.overlay)の具体例」をまとめて解説します!
1. Zephyrワークスペース全体の階層構造(Zephyr本体とアプリの位置関係)
Zephyr OSで開発を行う際、west ツールによって管理されるディレクトリ群を 「Zephyr ワークスペース(Workspace)」 と呼びます。
自作のアプリケーションは、Zephyr本体(ソースコードや各種ドライバ群)と同じワークスペースの中に配置されるか、あるいは外部アプリケーションとして配置されます。
最も標準的な「マルチリポジトリ(Zephyr本体と同階層に自作アプリを置く)構成」の全体イメージは以下の通りです。
my_zephyr_workspace/ <-- 【ワークスペースルート】(west init で作成)
├── .west/ <-- westの管理設定フォルダ
├── zephyr/ <-- ★ Zephyr OS本体 (カーネル, ドライバ, サンプル等)
│ ├── Kconfig
│ ├── CMakeLists.txt
│ ├── kernel/
│ ├── drivers/
│ ├── samples/
│ └── ...
├── modules/ <-- サードパーティ製ライブラリ (HAL, HAL-Nordic等)
├── bootloader/ <-- ブートローダ (MCUboot等)
│
└── my_app/ <-- ★ 【自作アプリケーションのディレクトリ】
├── CMakeLists.txt # ビルド設定(ビルドシステムの最上位)
├── prj.conf # Kconfig設定(OS機能のON/OFF)
├── app.overlay # DeviceTreeオーバーレイ(ハードウェア定義の追加・上書き)
└── src/
├── main.c # アプリケーションのメイン処理
├── sensor_thread.c # 各機能スレッド処理など
└── sensor_thread.hこの構成のポイント
zephyr/フォルダ:west initやwest updateを実行すると、GitHubから自動的にダウンロードされる Zephyr OSの本体リポジトリ です。開発者がこの中のコードを直接書き換えることは基本的になく、常に綺麗な状態(アップストリーム)に保ちます。my_app/フォルダ: ここが あなたが作成・Git管理する自分のアプリケーション です。- 位置関係:
my_app/はzephyr/と「兄弟(同階層)」の関係になります。CMakeLists.txt内のfind_package(Zephyr)が、自動的に親ディレクトリを辿って隣のzephyr/フォルダをOS本体として認識してくれます。
2. アプリ内(my_app/)の各ファイルの書き方
それでは、my_app/ の中に配置する各設定ファイルの具体的な記述方法を見ていきましょう。
① CMakeLists.txt(ビルド定義)
自作アプリのビルド設定ファイルです。「find_package(Zephyr) を呼び出す順番」が最大のポイントです。
# 1. 最低要求するCMakeのバージョンを指定
cmake_minimum_required(VERSION 3.20.0)
# 2. 隣にあるZephyr本体パッケージを自動探索・読み込み
# (※ target_sourcesより前に記述すること!)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
# 3. アプリケーション(プロジェクト)名の宣言
project(my_app)
# 4. アプリケーションのソースコードを追加
target_sources(app PRIVATE
src/main.c
src/sensor_thread.c
)
# 5. インクルードパスの追加(必要な場合)
target_include_directories(app PRIVATE src/)
💡 ポイント:
find_package(Zephyr)が実行されると、CMakeは隣にある../zephyr/ディレクトリを探索し、Zephyr本体のカーネルビルドシステムやKconfig/DeviceTree生成処理をすべて自動で読み込んで連結してくれます。
② prj.conf(Kconfig / ソフトウェア機能設定)
プロジェクトで有効化したいOS機能(GPIO, I2C, BLE, ログ機能等)を CONFIG_xxx=y の形式で指定します。
# ==========================================
# ログ出力・デバッグ機能
# ==========================================
CONFIG_LOG=y
CONFIG_LOG_MODE_IMMEDIATE=y
# ==========================================
# ハードウェアドライバの有効化
# ==========================================
CONFIG_GPIO=y
CONFIG_I2C=y
# ==========================================
# カーネル機能の設定
# ==========================================
CONFIG_PRINTK=y
# 画面UIで設定したい場合は `west build -t menuconfig` でグラフィカルに編集可能!
③ app.overlay(DeviceTreeオーバーレイ)
ターゲットボード(QEMUやマイコン実機)の標準DeviceTreeに対し、アプリ固有のピン定義やエイリアスを追加・改変します。
/ {
/* 1. アプリから参照しやすいようにエイリアス(別名)を定義 */
aliases {
status-led = &my_led;
};
/* 2. 独自のLEDノードを定義 */
leds {
compatible = "gpio-leds";
my_led: led_0 {
gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>;
label = "User Status LED";
};
};
};④ src/main.c(ソースコード)
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>
/* ログモジュールの登録 */
LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);
/* DeviceTreeのエイリアス "status-led" からピン情報を取得 */
#define LED_NODE DT_ALIAS(status_led)
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED_NODE, gpios);
int main(void)
{
LOG_INF("Zephyr アプリケーションを起動中...");
if (!gpio_is_ready_dt(&led)) {
LOG_ERR("エラー: GPIOデバイスの準備ができていません");
return 0;
}
gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
while (1) {
gpio_pin_toggle_dt(&led);
LOG_INF("LEDをトグルしました");
k_msleep(1000);
}
return 0;
}
3. ビルドと実行の手順
作成した自作アプリのディレクトリ(my_app/)へ移動して、west コマンドでビルド・実行します。
# 1. 自作アプリのディレクトリへ移動
cd my_zephyr_workspace/my_app
# 2. QEMU (x86) 向けにビルド
# (`west build` が自動で隣の `../zephyr` を認識してビルドします)
west build -b qemu_x86 .
# 3. QEMUでの実行
west build -t run
マイコン実機(STM32 NUCLEO等)に書き込む場合も、アプリディレクトリ内でターゲットボード名を指定するだけです。
# STM32 NUCLEO-F401RE 向けビルド
west build -b nucleo_f401re .
# 実機への書き込み
west flash
4. まとめ
Zephyr OSで開発を始めるときは、「ワークスペース(親)」の中に「Zephyr本体(OS)」と「自分のアプリ(コード)」が同階層で並ぶ という構造を理解しておくことが第一歩です。
zephyr/フォルダ(本体)は触らず、クリーンに保つmy_app/フォルダ(自分のアプリ)内にソース・CMake・prj.conf・overlay を閉じるCMakeLists.txtのfind_package(Zephyr)が自動的に両者を繋いでビルドする
この全体像さえ掴んでしまえば、ソースコードの共通化やマイコン移植、チームでのGit管理も非常にスムーズに行えます!


コメント