3、第一个 Zephyr 项目:使用 west 创建项目、构建、烧录、运行 hello_world,理解项目结构与构建系统
Zephyr RTOS 的工程实践与传统的嵌入式 IDE 开发模式有显著差异。它采用了一套基于 west 工具和 CMake 的模块化构建体系。对于初学者而言,理解这套体系的核心不在于记住每一个 CMake 变量,而在于建立“源码树(Workspace)”与“应用(Application)”分离的认知模型。本章将带领你从零开始,使用 west 命令行工具完成 hello_world 示例的创建、编译、烧录与运行,并深入剖析 Zephyr 项目的目录结构、west 工作流以及 Kconfig 与 Devicetree 在构建中的角色。下图展示了 Zephyr 项目从源码到目标板运行的完整工程链路。
上图清晰地展示了从 west init 到最终运行的完整链路。接下来,我们将分步骤拆解这一流程,并深入理解每个环节背后的设计逻辑。
3.1 核心原理:west 与 CMake 的分工协作
Zephyr 的构建系统并非从零发明,而是建立在 CMake 之上,并增加了 west 作为高层管理工具。理解两者的分工是掌握 Zephyr 开发的第一步。
- west(Zephyr's meta-tool):负责项目级管理。它处理多仓库的拉取(
west init/west update)、构建命令的封装(west build)、烧录与调试的调度(west flash/west debug)。west 本身不编译代码,它只是“指挥家”。 - CMake:负责构建级控制。它读取
CMakeLists.txt文件,结合 Zephyr 提供的zephyr.cmake模块,生成 Makefile 或 Ninja 构建脚本。CMake 处理源文件依赖、编译选项、链接脚本等底层细节。 - Ninja/Make:负责实际编译执行。Ninja 是默认的生成器,它以并行方式快速编译 C/ASM 源文件,最终链接生成 ELF 文件。
这种分层设计带来了显著优势:开发者无需关心底层编译命令,只需通过 west build 统一入口,即可完成从配置到产物的全流程。同时,CMake 的跨平台特性使得 Zephyr 可以轻松支持 Linux、Windows、macOS 主机环境。
3.2 操作流程:从零创建并运行 hello_world
下面以 nRF52840DK 开发板为例(其他板子只需更换 BOARD 变量),演示完整的操作流程。请确保已安装 Zephyr SDK 3.2 以上版本,并配置好 ZEPHYR_TOOLCHAIN_VARIANT 环境变量。
步骤 1:初始化工作区
# 创建并进入工作目录
mkdir zephyr-project && cd zephyr-project
# 初始化 west 工作区(拉取 manifest 仓库)
west init -m https://github.com/zephyrproject-rtos/zephyr --mr v3.5.0
# 拉取所有模块(zephyr、hal_nordic、mcuboot 等)
west update
west config 使用镜像源。例如:west config manifest.url https://ghproxy.com/https://github.com/zephyrproject-rtos/zephyr。另外,--mr 参数指定了 manifest 仓库的分支或标签,建议固定使用发布版本(如 v3.5.0)而非 main 分支,以保证模块兼容性。
步骤 2:创建应用目录
Zephyr 应用可以放在工作区内的任意位置,但推荐放在 app 子目录下,与 zephyr 主仓库平级。手动创建以下文件:
app/
├── CMakeLists.txt
├── prj.conf
└── src/
└── main.c
CMakeLists.txt 内容如下:
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(hello_world)
target_sources(app PRIVATE src/main.c)
prj.conf 内容(初始为空即可,hello_world 不需要额外配置):
# 空文件,或添加 CONFIG_PRINTK=y(默认已开启)
src/main.c 内容:
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
void main(void)
{
printk("Hello World! %s\n", CONFIG_BOARD);
while (1) {
k_sleep(K_MSEC(1000));
}
}
步骤 3:构建项目
# 进入应用目录
cd app
# 构建(指定目标板)
west build -b nrf52840dk_nrf52840
# 查看构建产物
ls build/zephyr/zephyr.elf build/zephyr/zephyr.bin
构建过程会输出大量日志,最后出现 Generating files done 和 Build complete 表示成功。如果出现错误,请检查 ZEPHYR_BASE 环境变量是否指向 zephyr 仓库路径。
步骤 4:烧录与运行
# 连接开发板(通过 USB 或 J-Link),烧录固件
west flash
# 查看串口输出(默认 115200 波特率)
west build -t run
west flash 会自动调用 J-Link 或 OpenOCD 烧录器。对于 nRF52840DK,默认使用 J-Link OB。烧录完成后,开发板自动复位运行,串口终端应输出:
*** Booting Zephyr OS build v3.5.0 ***
Hello World! nrf52840dk_nrf52840
west flash 报错 Error: J-Link not found,请检查 USB 连接和驱动。在 Linux 下可能需要添加 udev 规则。另外,west build -t run 需要配置串口终端(如 minicom 或 screen),否则输出无法显示。
3.3 案例拆解:构建系统如何“看到”你的硬件
很多初学者会困惑:为什么 west build -b nrf52840dk_nrf52840 就能自动识别板载 LED、UART 等外设?这背后是 Devicetree 与 Kconfig 的协同工作。我们以 hello_world 为例,拆解构建系统如何将硬件描述转化为可执行代码。
| 构建阶段 | 输入文件 | 输出产物 | 作用 |
|---|---|---|---|
| 1. Devicetree 解析 | boards/arm/nrf52840dk_nrf52840.dts | build/zephyr/zephyr.dts | 生成设备树二进制(DTB)和头文件 devicetree_generated.h |
| 2. Kconfig 配置 | prj.conf + Kconfig.* 文件 | build/zephyr/.config | 生成 autoconf.h,定义内核编译宏 |
| 3. CMake 生成 | CMakeLists.txt + zephyr.cmake | build/build.ninja | 生成编译规则,确定源文件列表和编译选项 |
| 4. 编译链接 | 所有 .c/.h 文件 | zephyr.elf / zephyr.bin | 生成最终固件,包含链接脚本和符号表 |
在 main.c 中,我们使用了 CONFIG_BOARD 宏,它来自 Kconfig 生成的 autoconf.h。而 printk 函数则通过 Devicetree 找到 UART 外设的基地址,并初始化驱动。整个过程中,开发者无需手动编写寄存器配置,只需关注应用逻辑。
app.overlay 文件,通过 west build -d build -b nrf52840dk_nrf52840 -- -DDTC_OVERLAY_FILE=app.overlay 指定。这种设计使得同一份应用代码可以适配不同硬件,只需更换 overlay 文件即可。
3.4 常见误区与总结复盘
在初学者实践中,以下问题出现频率最高,需要特别警惕:
- 误区一:直接修改 zephyr 仓库内的文件。 Zephyr 源码树是只读的,任何修改都会在
west update时被覆盖。正确的做法是在应用目录中通过 Kconfig 或 Devicetree overlay 进行配置。 - 误区二:混淆
west build与cmake。 不要手动运行cmake命令,除非你完全理解 Zephyr 的 CMake 模块。west 会自动设置ZEPHYR_BASE、BOARD等变量,手动操作极易出错。 - 误区三:忽略
prj.conf的作用。 很多外设驱动默认未启用,需要在prj.conf中添加CONFIG_XXX=y。例如使用 SPI 需要CONFIG_SPI=y,使用 GPIO 需要CONFIG_GPIO=y。 - 误区四:烧录后无输出就认为板子坏了。 首先检查串口终端波特率是否为 115200,其次确认
west flash是否成功(观察 J-Link 日志),最后检查prj.conf是否启用了CONFIG_PRINTK(默认开启)。
复盘总结:本章的核心目标是建立“west 管理项目,CMake 管理构建,Devicetree/Kconfig 描述硬件”的三层认知。通过 hello_world 的实践,你应该掌握以下技能:
- 使用
west init和west update搭建开发环境。 - 编写最小化的应用目录结构(CMakeLists.txt + prj.conf + main.c)。
- 使用
west build -b <board>构建固件,并定位构建产物。 - 使用
west flash烧录,并通过串口验证运行结果。 - 理解构建过程中 Devicetree 和 Kconfig 的输入输出关系。