Zephyr 开发进阶:设备树 DTS、板卡 BSP 与驱动模型全解析
本文深入剖析 Zephyr 系统中设备树(Devicetree)机制、板卡支持包(Board Support Package, BSP)结构与驱动模型的协作原理,结合实际项目中的自定义板卡与驱动开发需求,讲透 Zephyr 如何通过 DTS + Kconfig + CMake 三者协同实现平台适配、模块复用与硬件抽象。
一、设备树(Devicetree)在 Zephyr 中的定位
设备树是一种结构化的硬件描述机制,用于在编译期定义和传递硬件资源信息。相比裸 C 宏定义,它更标准、跨平台、可配置。
在 Zephyr 中,设备树配合以下机制共同构成了平台适配体系:
-
.dts
/.dtsi
:设备树源码 -
Kconfig
:配置条件使能/参数化设备功能 -
CMakeLists.txt
:描述工程依赖与构建逻辑
✅ DTS 用于描述什么?
-
板级资源:如 GPIO、串口、SPI、I2C、LED、PWM 等
-
片上外设:如 ADC、DMA、RTC 等模块使能与参数
-
外设挂载:如 OLED 显示屏、传感器、通信芯片等
Zephyr 构建系统将 .dts
编译为:
-
zephyr.dts
(展开后的设备树) -
devicetree_generated.h
(用于 C 代码引用)
二、设备树文件结构与继承机制
设备树由多个 .dts
/ .dtsi
文件组成,支持逐层继承。
示例结构:
boards/arm/nucleo_f401re/
├── nucleo_f401re.dts ← 板卡设备树主入口
├── nucleo_f401re_defconfig ← 默认 Kconfig 配置
├── board.cmake ← CMake 构建入口
设备树通常继承芯片系列定义:
#include <st/f4/stm32f401.dtsi>
三、如何添加一个自定义板卡 BSP
以 STM32F103C8T6(BluePill)为例:
步骤 1:创建 board 目录结构
boards/arm/bluepill/
├── bluepill.dts
├── bluepill_defconfig
├── Kconfig.board
├── board.cmake
步骤 2:编写 bluepill.dts
/dts-v1/;
#include <st/f1/stm32f103.dtsi>/ {model = "BluePill F103C8";compatible = "st,stm32f103c8", "st,stm32f1";chosen {zephyr,console = &usart1;zephyr,flash = &flash;zephyr,sram = &sram;};
};
步骤 3:配置 defconfig
CONFIG_SOC_SERIES_STM32F1X=y
CONFIG_SOC_STM32F103XC=y
CONFIG_BOARD_BLUEPILL=y
四、设备节点语法解构
&i2c1 {status = "okay";clock-frequency = <I2C_BITRATE_FAST>;ssd1306@3c {compatible = "solomon,ssd1306fb";reg = <0x3c>;label = "SSD1306";width = <128>;height = <64>;};
};
字段 | 含义 |
---|---|
&i2c1 | 引用已定义的控制器 |
status | 是否启用(okay/disabled) |
reg | 地址(通常是 I2C/SPI 编址) |
compatible | 设备类型,与驱动匹配键 |
label | 用于代码中引用的别名 |
五、如何在驱动中使用设备树节点
通过 DEVICE_DT_GET()
或 DEVICE_DT_INST_GET()
宏:
#include <zephyr/device.h>
#include <zephyr/devicetree.h>#define OLED_NODE DT_NODELABEL(ssd1306)
const struct device *oled_dev = DEVICE_DT_GET(OLED_NODE);
结合 device_is_ready()
判定设备状态。
六、驱动开发流程与结构
驱动文件结构推荐:
drivers/display/
├── ssd1306.c
├── Kconfig.ssd1306
├── ssd1306.h
驱动注册:
使用 DEVICE_DT_INST_DEFINE()
注册驱动:
DEVICE_DT_INST_DEFINE(0,&ssd1306_init,NULL,&data, &cfg,POST_KERNEL,CONFIG_DISPLAY_INIT_PRIORITY,&ssd1306_driver_api);
七、Kconfig 与驱动参数绑定
配合设备树,可以在驱动中引用 Kconfig 配置:
config SSD1306bool "Enable SSD1306 OLED driver"depends on I2C
在 C 代码中:
#if CONFIG_SSD1306
// Enable display init
#endif
用户可通过 menuconfig
调整配置选项。
八、overlay 应用:定制项目设备树
在 app/
目录添加:
app.overlay
示例:
&usart2 {current-speed = <115200>;status = "okay";
};
通过 west build
自动合并。
九、进阶实践建议
-
所有外设先查找是否已有 DTS 模板 + compatible 驱动
-
自定义驱动必须注册设备 + 实现 API struct + 提供 init 函数
-
使用
dtc
与menuconfig
检查设备配置是否生效 -
在 CI 中检查
.config
与zephyr.dts
变更差异追踪硬件适配问题
十、总结
模块 | 作用 |
---|---|
DTS (.dts/.dtsi) | 硬件资源声明与地址映射 |
Kconfig | 设备使能与参数配置 |
CMake | 构建逻辑与依赖描述 |
drivers/ | 实际驱动代码与 API 实现 |
Zephyr 通过 DTS + Kconfig + CMake 构建出一套高度解耦、易复用、平台可移植的硬件支持机制。
下一篇将讲解如何基于 Zephyr 创建 SoC 支持包(SoC series / SoC variant)与运行时中断、内核调度器调优策略。