ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Zephyr BSP: 19-手撕 struct device 的生成

Zephyr BSP: 19-手撕 struct device 的生成 摘要:本文深入剖析 Zephyr 设备模型的核心机制,完整追踪一个 Devicetree 节点从DEVICE_DT_DEFINE()宏展开,到最终生成 ELF 中struct device对象的全过程。文章从struct device的四个核心成员(config、data、api、state)入手,逐步拆解DEVICE_DT_DEFINE()的宏调用链,阐明 Device Symbol、Config/Data/API 分离设计、Init Entry、Dependency Handle 等关键概念,并厘清dependency ordinal与init priority的本质区别。最后通过简化版手撕示例和 ELF 符号验证,帮助读者建立从源码到固件的完整认知,为将公司 SoC 接入 Zephyr 打下坚实基础。从 DEVICE_DT_DEFINE() 手撕 struct device 的生成TL;DR(太长不看版)DEVICE_DT_DEFINE()是设备对象生成器,不是简单的struct device初始化,它向下调用DEVICE_DT_DEINIT_DEFINE()→Z_DEVICE_DEFINE(),最终生成 Device Object、Config、Data、API 和 Init Entry 五个部分。(见第三、四、十七节)DEVICE_DT_GET()在编译期解析为__device_dts_ord_xx,通过 Devicetree 宏直接取符号地址,不是运行时搜索设备。(见第七、八节)Config / Data / API 三者分离:config 是静态硬件配置(ROM/RO),data 是运行时状态(RAM),api 是驱动操作接口(RO),struct device只是持有这三个指针的中心节点。(见第九~十三节)Init Entry 与 Dependency Handles 是两条隐藏链:Init Entry 把初始化函数按 level + priority 放进 linker section,由 boot 阶段统一执行;Dependency Handles 记录设备间的依赖关系,用于设备排序与访问控制。(见十四~二十节)dependency ordinal≠init priority:前者回答"设备在依赖图中的身份编号",后者回答"初始化阶段何时执行",两者最终在设备初始化系统中汇合。(见二十一节)这一篇我们不再停留在:“Zephyr 有一个 struct device。”而是直接回答:一个 DTS 节点,究竟是如何一步一步变成最终 ELF 里的 struct device 对象的?核心目标是把这条链彻底打通:DTS │ ▼ DT_NODELABEL(uart0)│ ▼ DEVICE_DT_DEFINE(...)│ ▼ DEVICE_DT_DEINIT_DEFINE(...)│ ▼ Z_DEVICE_DEFINE(...)│ ├── struct device ├── device_config ├── device_data ├── driver API ├── init entry └── dependency handles │ ▼ 最终 ELF │ ▼\__device_dts_ord_xx │ ▼ struct device *一、先看最终目标:我们到底想生成什么?假设 Devicetree:usart1{status="okay";current-speed=115200;};然后 driver 中写:DEVICE_DT_DEFINE(DT_NODELABEL(usart1),uart_stm32_init,NULL,uart_data,uart_config,PRE_KERNEL_1,CONFIG_SERIAL_INIT_PRIORITY,uart_driver_api);最终我们希望得到一个类似这样的对象:structdevice__device_dts_ord_XX={.name="usart1",.config=uart_config,.api=uart_driver_api,.data=uart_data,.state=...,};但这里有一个非常重要的认知:你在源码中通常不会直接看到这样一个完整的 struct device 初始化器。因为 Zephyr 用了大量宏,把它拆成多个编译期对象。二、先回顾 struct deviceZephyr 的设备模型核心就是:struct device概念上可以简化成:structdevice{constchar*name;constvoid*config;constvoid*api;void*data;structdevice_state*state;};不同 Zephyr 版本的具体字段可能有所变化,所以这里重点不是字段数量,而是理解:struct device │ ├── config │ ├── data │ ├── api │ └── state其中:config硬件的静态配置:structuart_stm32_config{uintptr_tbase;...};通常放在只读区域。data运行时数据:structuart_stm32_data{...};通常位于 RAM。apidriver 对外暴露的操作:staticconststructuart_driver_apiuart_driver_api={.poll_in=...,.poll_out=...,...};stateZephyr 自己管理的 device state。例如:device initialized device initialization failed device power state三、真正关键的宏现在进入核心。你看到:DEVICE_DT_DEFINE(...)不要把它理解成:struct device xxx;而应该把它理解成:一个"设备对象生成器"。四、第一层:DEVICE_DT_DEFINE()概念上可以理解成:#define DEVICE_DT_DEFINE(node_id, init_fn, pm, data, config, level, prio, api, ...)它实际上会继续向下调用更底层的宏。典型结构可以抽象成:DEVICE_DT_DEFINE()│ ▼ DEVICE_DT_DEINIT_DEFINE()│ ▼ Z_DEVICE_DEFINE()│ ├──────────────┐ ▼ ▼ struct device dependency handles注意:真正值得研究的是 Z_DEVICE_DEFINE()。五、为什么不能直接写 struct device?假设我们自己写:
返回列表