Zephyr最简工程配置指南

Zephyr最简工程配置指南:x86平台+QEMU运行

引言

在Zephyr RTOS开发中,配置一个最简工程是学习和测试的最佳起点。本文将详细介绍如何配置一个最小化的Zephyr工程,仅使用x86平台,并在QEMU模拟器中运行。

这种配置方式具有以下优势:

  • 快速入门:无需硬件设备即可体验Zephyr
  • 资源高效:仅包含必要组件
  • 易于调试:QEMU提供完整的调试支持
  • 跨平台:可在Windows、Linux、macOS上运行

一、环境准备

1.1 安装必要依赖

bash 复制代码
# Ubuntu/Debian系统
sudo apt-get update && sudo apt-get install -y \
    git \
    cmake \
    ninja-build \
    gperf \
    ccache \
    python3 \
    python3-pip \
    python3-venv \
    device-tree-compiler \
    qemu-system-x86  # QEMU x86模拟器

# macOS系统(使用Homebrew)
brew install git cmake ninja gperf ccache python dtc qemu

# Windows系统
# 建议使用WSL2或直接安装Zephyr SDK

1.2 安装West工具

bash 复制代码
# 安装West
pip install west

# 验证安装
west --version

1.3 获取Zephyr源码(最小化)

bash 复制代码
# 创建工作目录
mkdir -p ~/zephyrproject && cd ~/zephyrproject

# 初始化West项目(只获取核心仓库)
west init -m https://github.com/zephyrproject-rtos/zephyr --mr main

# 配置只下载必要组件
west config manifest.project-filter -- -hal_* -lib_* -modules_*

# 更新代码(仅核心仓库)
west update --narrow

# 安装Python依赖
pip install -r zephyr/scripts/requirements.txt

二、最简工程结构

2.1 创建工程目录

bash 复制代码
# 创建工程目录
mkdir -p ~/zephyr-app && cd ~/zephyr-app

# 创建必要文件
touch CMakeLists.txt prj.conf src/main.c

2.2 工程文件结构

复制代码
zephyr-app/
├── CMakeLists.txt           # CMake配置文件
├── prj.conf                 # Kconfig配置文件
└── src/
    └── main.c               # 主程序入口

2.3 CMakeLists.txt配置

cmake 复制代码
# CMakeLists.txt

# 最低CMake版本要求
cmake_minimum_required(VERSION 3.20.0)

# 包含Zephyr构建系统
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})

# 项目名称
project(my_minimal_app)

# 添加源文件
target_sources(app PRIVATE src/main.c)

2.4 prj.conf配置(最简配置)

conf 复制代码
# prj.conf - 最简配置

# 基础配置
CONFIG_SOC_POSIX=y
CONFIG_BOARD_QEMU_X86=y

# 内核配置
CONFIG_KERNEL=y
CONFIG_INIT_STACKS=y

# 控制台输出
CONFIG_CONSOLE=y
CONFIG_SERIAL=y
CONFIG_UART_CONSOLE=y

# 调试配置
CONFIG_DEBUG=y
CONFIG_DEBUG_OPTIMIZATIONS=y

# 系统时钟
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=100000000

# 定时器
CONFIG_TIMER=y
CONFIG_SYS_CLOCK_TICKS_PER_SEC=100

三、编写最简应用代码

3.1 main.c 最小实现

c 复制代码
/* src/main.c - 最简Zephyr应用 */

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>

/* 定义线程栈大小 */
#define STACKSIZE 1024

/* 定义线程优先级 */
#define PRIORITY 7

/* 线程函数 */
void main_thread(void)
{
    int count = 0;
    
    while (1) {
        printk("Hello Zephyr! Count: %d\n", count++);
        k_msleep(1000);
    }
}

/* 定义线程 */
K_THREAD_DEFINE(main_tid, STACKSIZE,
                main_thread, NULL, NULL, NULL,
                PRIORITY, 0, K_NO_WAIT);

/* 主入口函数 */
void main(void)
{
    printk("Zephyr minimal app started!\n");
}

3.2 代码解释

部分 说明
#include <zephyr/kernel.h> 内核API头文件
#include <zephyr/sys/printk.h> 打印函数头文件
K_THREAD_DEFINE 定义静态线程
k_msleep() 毫秒级延时函数
printk() 内核打印函数

四、编译配置

4.1 设置环境变量

bash 复制代码
# 设置Zephyr基础路径
export ZEPHYR_BASE=~/zephyrproject/zephyr

# 设置SDK路径(如果需要)
# export ZEPHYR_SDK_INSTALL_DIR=/opt/zephyr-sdk-0.17.2

# 验证设置
echo $ZEPHYR_BASE

4.2 编译命令

bash 复制代码
# 进入工程目录
cd ~/zephyr-app

# 编译(指定qemu_x86目标板)
west build -b qemu_x86 .

# 查看编译结果
ls -la build/zephyr/

4.3 编译输出

bash 复制代码
# 编译成功输出示例
[100%] Linking C executable zephyr/zephyr.elf
[100%] Built target zephyr

五、在QEMU中运行

5.1 运行命令

bash 复制代码
# 方式1:使用west run命令
west build -t run

# 方式2:手动运行QEMU
qemu-system-i386 \
    -cpu qemu32 \
    -nographic \
    -kernel build/zephyr/zephyr.elf \
    -machine pc

# 方式3:带调试端口运行
qemu-system-i386 \
    -cpu qemu32 \
    -nographic \
    -kernel build/zephyr/zephyr.elf \
    -machine pc \
    -s -S

5.2 运行输出

bash 复制代码
# 预期输出
SeaBIOS (version rel-1.16.0-0-gd239552ce722-prebuilt.qemu.org)
Booting from ROM..
*** Booting Zephyr OS build zephyr-v3.5.0-xxx ***
Zephyr minimal app started!
Hello Zephyr! Count: 0
Hello Zephyr! Count: 1
Hello Zephyr! Count: 2
...

5.3 退出QEMU

bash 复制代码
# 按 Ctrl+A 然后按 X 退出QEMU

六、调试配置

6.1 使用GDB调试

bash 复制代码
# 启动QEMU并监听调试端口
qemu-system-i386 \
    -cpu qemu32 \
    -nographic \
    -kernel build/zephyr/zephyr.elf \
    -machine pc \
    -s -S &

# 启动GDB
gdb-multiarch build/zephyr/zephyr.elf

# GDB命令
(gdb) target remote localhost:1234
(gdb) break main
(gdb) continue
(gdb) info threads
(gdb) next
(gdb) print count

6.2 VS Code调试配置

创建 .vscode/launch.json

json 复制代码
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Zephyr QEMU Debug",
            "type": "cppvsdbg",
            "request": "launch",
            "program": "${workspaceFolder}/build/zephyr/zephyr.elf",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "preLaunchTask": "build",
            "MIMode": "gdb",
            "miDebuggerPath": "gdb-multiarch",
            "miDebuggerServerAddress": "localhost:1234",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ]
        }
    ]
}

七、进阶配置

7.1 添加shell支持

修改 prj.conf

conf 复制代码
# 添加shell支持
CONFIG_SHELL=y
CONFIG_SHELL_BACKEND_SERIAL=y
CONFIG_SHELL_PROMPT="zephyr> "

运行效果:

bash 复制代码
*** Booting Zephyr OS build zephyr-v3.5.0-xxx ***
Zephyr minimal app started!
zephyr> help
Available commands:
  help    : print this help
  kernel  : kernel commands
  version : print kernel version
zephyr> kernel threads
Threads:
  0x200003e0 main_tid  prio=7
  0x20000100 idle     prio=31
zephyr>

7.2 添加定时器功能

c 复制代码
/* 在main.c中添加定时器 */

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>

#define TIMER_STACKSIZE 512
#define TIMER_PRIORITY 5

struct k_timer my_timer;

void timer_expiry_fn(struct k_timer *timer_id)
{
    printk("Timer expired!\n");
}

void timer_stop_fn(struct k_timer *timer_id)
{
    printk("Timer stopped!\n");
}

K_TIMER_DEFINE(my_timer, timer_expiry_fn, timer_stop_fn);

void main(void)
{
    printk("Starting timer...\n");
    k_timer_start(&my_timer, K_SECONDS(1), K_SECONDS(1));
    
    while (1) {
        k_msleep(500);
    }
}

7.3 添加线程间通信

c 复制代码
/* 添加信号量示例 */

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>

#define STACKSIZE 1024
#define PRIORITY 7

K_SEM_DEFINE(my_sem, 0, 1);

void thread1(void)
{
    while (1) {
        printk("Thread 1: Waiting for semaphore\n");
        k_sem_take(&my_sem, K_FOREVER);
        printk("Thread 1: Got semaphore\n");
        k_msleep(1000);
    }
}

void thread2(void)
{
    while (1) {
        printk("Thread 2: Giving semaphore\n");
        k_sem_give(&my_sem);
        k_msleep(2000);
    }
}

K_THREAD_DEFINE(thread1_tid, STACKSIZE, thread1, NULL, NULL, NULL, PRIORITY, 0, K_NO_WAIT);
K_THREAD_DEFINE(thread2_tid, STACKSIZE, thread2, NULL, NULL, NULL, PRIORITY + 1, 0, K_NO_WAIT);

void main(void)
{
    printk("Thread communication example\n");
}

八、常见问题与解决方案

8.1 QEMU未找到

问题qemu-system-i386: command not found

解决

bash 复制代码
# Ubuntu/Debian
sudo apt-get install qemu-system-x86

# macOS
brew install qemu

# 验证安装
qemu-system-i386 --version

8.2 编译错误 - 缺少工具链

问题arm-zephyr-eabi-gcc: command not found

解决

bash 复制代码
# 对于x86平台,通常不需要额外工具链
# 如果需要SDK,安装Zephyr SDK
wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.17.2/zephyr-sdk-0.17.2-setup.run
chmod +x zephyr-sdk-0.17.2-setup.run
./zephyr-sdk-0.17.2-setup.run --include-i686 --include-qemu

8.3 链接错误 - undefined reference

问题undefined reference to 'printk'

解决

conf 复制代码
# 在prj.conf中添加
CONFIG_CONSOLE=y
CONFIG_SERIAL=y
CONFIG_UART_CONSOLE=y

8.4 QEMU运行无输出

问题:运行QEMU后没有输出

解决

bash 复制代码
# 确保使用-nographic选项
qemu-system-i386 -nographic -kernel build/zephyr/zephyr.elf

# 检查串口配置
# 在prj.conf中添加
CONFIG_UART_CONSOLE_ON_DEV_NAME="uart0"

九、最简工程模板

9.1 完整工程打包

bash 复制代码
# 创建模板目录结构
mkdir -p zephyr-minimal-app/{src,config}
cd zephyr-minimal-app

# 创建CMakeLists.txt
cat > CMakeLists.txt << 'EOF'
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(minimal_app)
target_sources(app PRIVATE src/main.c)
EOF

# 创建prj.conf
cat > prj.conf << 'EOF'
CONFIG_SOC_POSIX=y
CONFIG_BOARD_QEMU_X86=y
CONFIG_KERNEL=y
CONFIG_INIT_STACKS=y
CONFIG_CONSOLE=y
CONFIG_SERIAL=y
CONFIG_UART_CONSOLE=y
CONFIG_DEBUG=y
CONFIG_DEBUG_OPTIMIZATIONS=y
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=100000000
CONFIG_TIMER=y
CONFIG_SYS_CLOCK_TICKS_PER_SEC=100
EOF

# 创建main.c
cat > src/main.c << 'EOF'
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>

#define STACKSIZE 1024
#define PRIORITY 7

void main_thread(void)
{
    int count = 0;
    while (1) {
        printk("Hello Zephyr! Count: %d\n", count++);
        k_msleep(1000);
    }
}

K_THREAD_DEFINE(main_tid, STACKSIZE, main_thread, NULL, NULL, NULL, PRIORITY, 0, K_NO_WAIT);

void main(void)
{
    printk("Zephyr minimal app started!\n");
}
EOF

echo "Minimal Zephyr app created successfully!"

9.2 使用模板

bash 复制代码
# 使用模板创建工程
mkdir -p ~/myapp && cd ~/myapp
cp -r /path/to/zephyr-minimal-app/* .

# 设置环境变量
export ZEPHYR_BASE=~/zephyrproject/zephyr

# 编译运行
west build -b qemu_x86 .
west build -t run

十、性能优化建议

10.1 优化编译配置

conf 复制代码
# prj.conf - 优化配置

# 关闭调试信息(发布版本)
CONFIG_DEBUG=n
CONFIG_DEBUG_OPTIMIZATIONS=n
CONFIG_OPTIMIZE_FOR_SIZE=y

# 关闭不需要的功能
CONFIG_ASSERT=n
CONFIG_LOG=n
CONFIG_SHELL=n

# 优化内存
CONFIG_HEAP_MEM_POOL_SIZE=2048
CONFIG_KERNEL_MEM_POOL_SIZE=1024

10.2 优化代码

c 复制代码
// 优化后的main.c

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>

#define STACKSIZE 512  // 减小栈大小
#define PRIORITY 7

void main_thread(void)
{
    static int count;  // 使用静态变量节省栈空间
    
    for (;;) {
        printk("Count: %d\n", count++);
        k_sleep(K_MSEC(1000));  // 使用k_sleep替代k_msleep
    }
}

K_THREAD_DEFINE(main_tid, STACKSIZE, main_thread, NULL, NULL, NULL, PRIORITY, 0, K_NO_WAIT);

void main(void) { }  // 简化主函数

结束语

通过本文的介绍,您已经掌握了如何配置一个最简的Zephyr工程:

步骤 内容
环境准备 安装QEMU、West工具
工程结构 CMakeLists.txt + prj.conf + src/main.c
编译命令 west build -b qemu_x86 .
运行命令 west build -t run
调试方法 GDB + QEMU远程调试

最简工程的优势:

  1. 快速上手:无需硬件设备,QEMU即可运行
  2. 资源高效:只包含必要组件,编译速度快
  3. 易于学习:代码量少,便于理解Zephyr核心概念
  4. 可扩展性:可以逐步添加功能

建议在掌握最简工程后,尝试添加更多功能:

  • Shell交互
  • 定时器
  • 线程间通信
  • 文件系统
  • 网络功能

参考资料

相关推荐
ScilogyHunter3 小时前
Zephyr主仓库目录结构完全指南
zephyr
ScilogyHunter4 小时前
Zephyr工程配置完全指南
zephyr
ScilogyHunter5 小时前
Zephyr SDK按需配置完全指南
zephyr
ScilogyHunter5 小时前
Zephyr编译生成的build目录完全解析
zephyr
ScilogyHunter6 小时前
Zephyr开发中的Manifest文件完全解析
manifest·zephyr·west
ScilogyHunter1 天前
Zephyr概述
zephyr
ScilogyHunter1 天前
Zephyr SDK 目录结构详解
zephyr
ScilogyHunter1 天前
Zephyr Shell完全指南
shell·zephyr
ScilogyHunter1 天前
West工具完全指南
zephyr·west