Zephyr BSP: 16-Zephyr Devicetree to C 代码生成全过程
摘要:本文深入剖析 Zephyr RTOS 中 Devicetree 从.dts文本到 C 代码中DT_*宏的完整生成链路。文章从整体流水线出发,依次讲解.dts/.dtsi/.overlay的合并与预处理、zephyr.dts与devicetree_generated.h的区别、EDT(Enhanced Devicetree)对象模型、Binding 的作用,以及DT_NODELABEL()、DT_PATH()、DT_ALIAS()、DT_CHOSEN()、DT_INST()、DT_REG_ADDR()、DT_IRQN()、DT_PROP()等核心宏的由来与用法。最终串联 Init Priority、Driver Dependency、Dependency Graph,揭示DEVICE_DT_DEFINE()如何将 Devicetree 节点转化为struct device,并给出 BSP 开发调试的实用检查清单。Zephyr Devicetree → C 代码生成全过程你前面已经把:13 Init Priority→14 Driver Dependency→15 Devicetree Dependency Graph串起来了。下一步非常关键:Devicetree 文件到底是怎么一步一步变成 C 代码里的 DT_NODELABEL()、DT_INST()、DT_PROP()、DEVICE_DT_DEFINE() 的?这篇建议重点解决一个问题:.dts 是文本,最终却能让 C 编译器看到各种 DT_* 宏。中间到底发生了什么?1. 先看完整流水线先建立一张总图:Devicetree Source │ │ ▼ board.dts / .dtsi │ │ │ C preprocessor │ ▼ merged devicetree │ │ ▼ dtc / edtlib │ ┌─────────────┴─────────────┐ │ │ ▼ ▼ zephyr.dts edt.pickle │ │ │ │ ▼ ▼ devicetree_generated.h Python EDT │ │ │ │ └─────────────┬─────────────┘ │ ▼ Zephyr build system │ ▼ C/C++ compiler │ ▼ Driversource│ ▼ DEVICE_DT_DEFINE(...)│ ▼ struct device │ ▼ final firmware这里最容易产生一个误解:Zephyr 不是简单地把 .dts 转换成一个 .h。实际上存在两条重要路线:DTS │ ┌────────┴────────┐ │ │ ▼ ▼ devicetree.h Python EDT │ │ │ └── binding / dependency / │ instance / property analysis │ ▼ C preprocessor │ ▼ DT_* macros │ ▼ Driver C code而EDT(Enhanced Devicetree)是理解现代 Zephyr Devicetree 的关键。2. 第一层:.dts 到底是什么?例如我们有:/{soc{uart0:serial@40004000{compatible="company,my-uart";reg=0x400040000x1000;interrupts=5;clock-frequency=48000000;status="okay";};};};这里描述的是:Node ├── name │ └── serial@40004000 │ ├── label │ └── uart0 │ ├── compatible │ └── company,my-uart │ ├── reg │ └── 0x40004000 0x1000 │ ├── interrupts │ └──5│ ├── clock-frequency │ └──48000000│ └── status └── okay注意:Devicetree 本身不是 C。它只是一个硬件描述语言。所以:DT_NODELABEL(uart0)并不是 .dts 里面天然存在的东西。它是 Zephyr 后续生成出来的C 宏接口。3. 第二层:.dtsi 和 .dts 先合并真实 Zephyr 项目中,通常不是一个 DTS 文件。例如:boards/ company/ my_board/ my_board.dts里面可能:#includelt;company/soc.dtsigt;uart0{status="okay";};而:soc.dtsi里面可能已经定义:uart0: serial@40004000{compatible="company,my-uart";reg=...;};所以最终并不是分别处理:soc.dtsi my_board.dts而是先形成:soc.dtsi │ │ board.dts │ ▼ C preprocessor │ ▼ merged DTSsource可以理解为:SoC 描述 + Board 描述 + Shield + overlay + chosen + aliases + 其他 .dtsi │ ▼ 最终 Devicetree4. Overlay 在什么时候进入?比如:boards/company/my_board/my_board.dts定义:uart0{status="okay";};你的应用又有:app.overlay里面:uart0{current-speed=lt;115200gt;;};最终得到:uart0 ├── compatible="company,my-uart"├── reg=...├── status="okay"└── current-speed=115200所以 overlay 并不是运行时配置。它是在build time修改 Devicetree。这一点非常重要:overlay │ ▼ buildtime│ ▼ Devicetree 被修改 │ ▼ C code 使用最终结果而不是:firmware running │ ▼ 读取 overlay完全不是这样。5. 第三层:C preprocessor 处理 DTS这是理解 Zephyr BSP 的一个关键点。Devicetree 的预处理阶段会处理:# include# define# if# ifdef之类的东西。因此:board.dts │ ├── include soc.dtsi ├── include bindings └── overlay │ ▼ preprocessed DTS之后才交给 Devicetree compiler / Zephyr Devicetree tooling。6. 第四层:生成 zephyr.dts构建过程中你通常可以在:build/zephyr/附近看到:zephyr.dts这个文件非常值得你直接打开看。它代表:最终合并之后的 Devicetree。例如:soc{uart0: serial@40004000{compatible="company,my-uart";reg=0x40004000 0x1000;interrupts=5;status="okay";};};此时:.dts .dtsi .overlay │ ▼ 最终 Devicetree │ ▼ build/zephyr/zephyr.dts7. zephyr.dts 和 devicetree_generated.h 不一样这是很多刚开始研究 Zephyr 的人最容易混淆的地方。你可以把它们理解成:zephyr.dts给人和 Devicetree 工具看的:Node ├── compatible ├── reg ├── interrupts ├── status └── propertiesdevicetree_generated.h给 C 编译器看的:# define DT_N_S_soc_S_serial_40004000 ...# define DT_N_S_soc_S_serial_40004000_REG_ADDR ...# define DT_N_S_soc_S_serial_40004000_IRQ ...也就是说:zephyr.dts │ │ Devicetree representation ▼ devicetree_generated.h │ │ C macro representation ▼ Csource8. 最关键的文件:devicetree_generated.h假设:uart0: serial@40004000{compatible="company,my-uart";reg=0x40004000 0x1000;interrupts=5;status="okay";};Zephyr 会生成大量宏。概念上类似:# define DT_N_S_soc_S_serial_40004000 ...然后:DT_NODELABEL(uart0)最终会通过宏展开找到对应 node identifier。9. 为什么 Devicetree Node 会变成奇怪的宏名字?这是 Zephyr Devicetree 最值得理解的机制之一。假设:soc{uart0: serial@40004000{...};};它有一个完整 path:/soc/serial@40004000Zephyr 需要把这个路径编码成 C identifier。于是概念上变成:/soc/serial@40004000 ↓ DT_N_S_soc_S_serial_40004000这里:/ → S @ → 处理成合法 identifier\- → 处理成合法 identifier具体编码规则比较复杂,但核心思想非常简单:把 Devicetree path 编码成合法的 C identifier。所以:Devicetreenode↓ canonicalnodeidentifier ↓ C preprocessor macro10. DT_NODELABEL(uart0) 是怎么来的?你写:# define UART_NODE DT_NODELABEL(uart0)看起来像:uart0直接变成 node。其实不是。可以把它理解成:DT_NODELABEL(uart0)│ ▼ DT_N_NODELABEL_uart0 │ ▼ DT_N_S_soc_S_serial_40004000也就是说:

相关新闻

AI眼镜PCBA代工怎么选?天地通 vs 通用方案深度对比

AI眼镜PCBA代工怎么选?天地通 vs 通用方案深度对比

开头 AI眼镜正从概念走向量产,其控制板对SMT贴片加工提出了极高要求:微型化、高密度、高可靠。面对市场上众多的PCBA代工厂,决策者常陷入两难:是选择深耕智能硬件的专业厂,还是走通用型代工路线?本文从技术…

2026/10/2 20:41:58 阅读更多 →
仿muduo高并发网络库——Poller和EpollPoller

仿muduo高并发网络库——Poller和EpollPoller

一、Poller(IO 多路复用抽象基类)// Poller 是抽象基类(可以用 epoll 也可以用 poll 实现) class Poller { public:Poller();virtual ~Poller();作用 :定义抽象基类- virtual ~Poller() :虚析构函数&#x…

2026/10/2 20:41:59 阅读更多 →
从拓扑到仿真:网络图论与大规模电路计算机辅助分析【系统进阶付费专栏】

从拓扑到仿真:网络图论与大规模电路计算机辅助分析【系统进阶付费专栏】

专栏定位:面向电子工程、自动化、集成电路、电力系统专业的学生与工程师,从基础概念到代码实战,系统拆解网络图论的核心原理与工业落地方法,彻底搞懂电路仿真器的底层数学逻辑,掌握大规模电路自动分析的完整流程。 全专栏共 14 篇,采用循序渐进的连载模式,每周更新 2 篇…

2026/10/4 5:43:25 阅读更多 →

最新新闻

Java+JSP+MySQL电子健康档案系统毕业设计实现与避坑指南

Java+JSP+MySQL电子健康档案系统毕业设计实现与避坑指南

简介:这份资源是面向高校计算机专业学生与Java Web初学者的毕业设计实践包,主题为基于JavaJSPMySQL的电子健康档案系统,可用于课程设计、毕设选题或医疗机构信息化入门参考。压缩包共760个文件,约17.76MB,以js脚本、gi…

2026/10/5 14:28:57 阅读更多 →
基于Java+JSP+MySQL的电子健康档案系统:从建库到答辩的完整实现

基于Java+JSP+MySQL的电子健康档案系统:从建库到答辩的完整实现

简介:这份资源是面向高校计算机相关专业学生与Java Web初学者的毕业设计实践包,主题为基于JavaJSPMySQL的电子健康档案系统,可用于课程设计、毕设选题或医疗机构信息化入门参考。压缩包共760个文件,约17.76MB,以js脚本…

2026/10/5 14:28:57 阅读更多 →
彩虹易支付可运营源码搭建保姆级教程:从环境配置到支付安全

彩虹易支付可运营源码搭建保姆级教程:从环境配置到支付安全

简介:这份资源提供的是已测最新版、可运营的彩虹易支付源码,并搭配保姆级搭建教程,面向需要个人免签支付方案的个人开发者、中小站长与技术学习者。源码内置24个支付插件,接入微信、QQ、支付宝等主流渠道,具备轮训支付…

2026/10/5 14:28:57 阅读更多 →
JSP+SQLServer高校科研项目管理系统毕业设计实战:从环境搭建到答辩避坑

JSP+SQLServer高校科研项目管理系统毕业设计实战:从环境搭建到答辩避坑

简介:这份资源是面向高校计算机相关专业毕业设计场景的Java JSP高校科研项目管理系统,采用SQLServer数据库,基于JDK1.8开发,可在Eclipse、MyEclipse、STS或IDEA等常见工具中运行,适合需要完成课题申报、成果管理与论文…

2026/10/5 14:28:57 阅读更多 →
SAP ABAP开发:用BAPI_PO_CREATE1批量创建委外采购订单

SAP ABAP开发:用BAPI_PO_CREATE1批量创建委外采购订单

1. 项目概述1.1 核心需求解析做SAP运维或者开发的同行,对“委外采购订单”这个名字绝对不陌生。它和普通采购订单最大的区别在于:你不是直接买一个现成的成品,而是把原材料发给供应商,让供应商加工成半成品或者成品再送回你的仓库…

2026/10/5 14:28:56 阅读更多 →
Javaweb物流管理系统实战:从运行配置到数据库设计全解析

Javaweb物流管理系统实战:从运行配置到数据库设计全解析

简介:这是一份基于JavaWeb技术栈的物流管理系统完整项目资料,面向初、中级Java开发者和毕业设计/课程设计人群,覆盖订单管理、仓储管理、配送跟踪等核心业务。压缩包共717个文件,包含Java源码、JSP页面、SQL数据库脚本、XML配置以…

2026/10/5 14:27:56 阅读更多 →

日新闻

马斯克杀回智能体战场,Grok 4.5万亿参数撑腰,Cursor接手数字白领项目:用TaoToken统一Key跑通多模型Agent工作流

马斯克杀回智能体战场,Grok 4.5万亿参数撑腰,Cursor接手数字白领项目:用TaoToken统一Key跑通多模型Agent工作流

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 0:00:22 阅读更多 →
AI编程工具插件机制详解:plugin.json配置与加载失败排查指南

AI编程工具插件机制详解:plugin.json配置与加载失败排查指南

1. 从“plugins”这个词说起:它到底在解决什么问题如果你最近在折腾 AI 编程工具,尤其是 Cursor、Codex CLI、Claude Code 这类带 CLI 的编辑器或命令行助手,那你大概率绕不开一个词——plugins。这个词本身不新鲜,从浏览器到 IDE…

2026/10/5 0:00:23 阅读更多 →
第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单

第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 0:00:23 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 5:06:42 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 1:10:22 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 3:06:17 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 11:40:45 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 9:43:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 20:14:29 阅读更多 →