新闻详情

新闻详情

首页 / 资讯中心 / 详情

Zephyr BSP: 16-Zephyr Devicetree to C 代码生成全过程

发布时间:2026/9/29 10:52:30来源:尧图网络
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也就是说:
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

一审刑辩律师事务所行业口碑汇总:广受信赖的资深律师团队怎么选 2026/9/29 12:10:52

一审刑辩律师事务所行业口碑汇总:广受信赖的资深律师团队怎么选

最近不少当事人家属后台咨询,找一审刑辩律师事务所最看重的是什么?怎么才能找到真正专业、靠谱、能帮当事人争取从轻结果的团队?今天整理了行业内大家认可度比较高的选所标准,也帮大家解答几个选一审刑辩律师事务所最常见的问题。Q1:规模大…

阅读更多 →
EtherCAT实时总线实战:从同步原理到CSP模式与从站开发调试 2026/9/29 12:10:52

EtherCAT实时总线实战:从同步原理到CSP模式与从站开发调试

其实一开始接触EtherCAT,我是被逼的。当时在给一台23轴的贴片设备换控制系统,老方案是脉冲加CANopen混搭:伺服一多,启停同步总是差那么几个毫秒,飞达一开料带就歪,良率上不去。后来整套换成EtherCAT&#x…

阅读更多 →
RK3588双路视觉丢旧帧背压方案:解决队列积压与延迟飙升 2026/9/29 12:10:33

RK3588双路视觉丢旧帧背压方案:解决队列积压与延迟飙升

双路视觉系统跑在香橙派RK3588上,最让人头疼的不是模型推理本身,而是两路摄像头帧率不一致时引发的连锁反应。我最近在调一套双路YOLOv5s检测方案,阶段一跑通之后发现一个很隐蔽的问题:当其中一路摄像头因为曝光调整或者USB带宽抖…

阅读更多 →
Altium Designer 26.3 安装全流程与避坑指南:从环境准备到许可证配置 2026/9/29 12:10:33

Altium Designer 26.3 安装全流程与避坑指南:从环境准备到许可证配置

1. 为什么AD 26的安装值得单独写一篇完整记录Altium Designer 26.3(圈内一般直接叫AD 26)是Altium官方在2025年推出的主力版本,相比AD 20、AD 21那一代,26版本在安装机制上做了几处比较明显的调整:安装包体积进一步膨胀…

阅读更多 →
免费提词器怎么选?零基础小白避坑指南 2026/9/29 12:10:26

免费提词器怎么选?零基础小白避坑指南

阅读更多 →
汽车传感器与执行器全链路设计原理与实战 2026/9/29 12:10:26

汽车传感器与执行器全链路设计原理与实战

1. 这本教材到底讲什么?为什么汽车电子工程师案头都摆着它“Automotive Sensors and Actuators: Principles, Systems, and Electronics”——光看这个标题,你可能觉得又是一本堆满公式、配图模糊、翻两页就想合上的教科书。但我在整车厂做电控系统集成的…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉