跳到主要内容

系统架构

用裸机方式写程序时,你可能在 main 中初始化时钟、GPIO,再进入死循环。Zephyr 保留应用入口,但在调用 main 前已经完成内核、线程环境和一批设备初始化。应用不需要重新实现调度器或为每个外设手写寄存器操作。

软件分层​

通常情况下,应用、被选中的内核功能和驱动会一起编译、链接成固件,烧录后运行在 MCU 上。它不是在 Linux 上启动一个普通进程,也不是把 C 源码复制到板上解释执行。

从圆屏示例看,各层分工如下:

层次本例对应内容你通常修改什么
应用创建圆环、响应按钮、显示数值main.c 及自己的业务代码
库/子系统LVGL、日志、输入处理Kconfig 配置及调用方式
驱动GC9A01、CST8XX、SPI、GPIO优先使用 API;缺驱动才新增
板卡屏幕连到哪条 SPI、哪个 GPIO 是背光DTS、pinctrl、板卡默认配置
SoC / 架构ESP32-S3 寄存器、IRQ、Xtensa 上下文普通板卡适配通常复用
内核调度、线程、时间、同步通过内核 API 使用

设备树与 Kconfig 参与构建,不是运行中的额外两个服务。设备树提供硬件实例信息,Kconfig 决定哪些实现参与构建。

源码目录​

进入 main 工作区的 zephyr 目录:

cd ~/Projects/zephyr-main-workspace/zephyr
ls kernel drivers subsys soc arch boards include samples

不要一开始从头读完整个 kernel。先从自己应用用到的函数往下找,例如:

rg 'k_sleep' include/zephyr/kernel.h
rg 'gpio_pin_set_dt' include/zephyr/drivers/gpio.h
rg 'zephyr,display|zephyr,touch' boards/waveshare/esp32s3_touch_lcd_1_28

include/zephyr/ 是常用 API 的入口;drivers/ 是具体实现;boards/ 描述板级连接;工作区外层的 modules/ 是依赖仓库,不要误认为这里缺少 LVGL。

启动流程​

对本板的 Simple boot 构建,可以先按下列顺序理解:

芯片 ROM 根据启动引脚决定下载或从 Flash 启动
→ 固件启动代码准备内存、CPU 和系统基础设施
→ Zephyr 初始化内核及按阶段安排的设备
→ main 线程执行应用 main()
→ 应用线程与系统线程由调度器运行

其他板卡或 MCUboot 构建还会有不同的启动链。看到 ROM 的 waiting for download,说明还没有运行应用;这时改 LVGL 或线程优先级不会解决问题。

驱动初始化可发生在 main 前,main 内仍要用 device_is_ready() 检查。设备实例存在不代表初始化成功。

配置与构建流程​

板卡 DTS + SoC DTSI + 应用 overlay → zephyr.dts → 设备树生成头文件
板卡默认配置 + prj.conf + Kconfig 规则 → .config → autoconf.h
应用 C + 驱动 C + 内核 C + 库 → 编译/链接 → ELF/BIN

例如你想显示文字:硬件配置必须有可用的显示设备,软件配置必须启用 DISPLAY、LVGL 及所需控件,应用还必须创建文字并处理刷新。只打开一个开关不会自动生成界面。

练习​

打开现有 LVGL 构建目录的 zephyr/.config,找到 DISPLAY 与 LVGL;打开 zephyr/zephyr.dts,找到 chosen 的 display 引用;回到 main.c 找到 DEVICE_DT_GET(DT_CHOSEN(zephyr_display))。把这三处连起来,才能知道程序操作的是哪块屏幕。

下一步:建立自己的应用。

参考:本机 include/zephyr/、kernel/init.c、板卡 DTS,以及 Zephyr 应用开发。