尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Zephyr BSP: 15-Zephyr Devicetree Dependency Graph

Zephyr BSP: 15-Zephyr Devicetree Dependency Graph 摘要:本文从clocks = clock0这一行出发,系统讲解 Zephyr Devicetree 依赖图的完整链路。首先通过真实例子认识phandle如何表达设备间的依赖关系;接着解释 Zephyr 为什么需要dependency ordinal作为 Devicetree node 的内部编号;随后说明device handle如何描述设备依赖,并最终通过DEVICE_DT_DEFINE()生成struct device、通过DEVICE_DT_GET()获取设备对象。文章还厘清了dependency ordinal与初始化优先级、DEVICE_DT_GET()与依赖关系等易混概念,最后给出编写公司 SoC BSP 时应遵循的「三层模型」原则:让 DTS 描述依赖、让 Driver 描述操作。Zephyr Devicetree Dependency Graph1. 先看一个真实的例子假设我们有:uart0:uart@40004000{compatible="mycompany,my-uart";reg=0x400040000x1000;clocks=clock0;interrupts=5;status="okay";};同时:clock0:clock@40000000{compatible="mycompany,my-clock";reg=0x400000000x1000;status="okay";};这里最重要的一行:clocks=clock0;clock0 就是一个phandle。它表达的是:UART0 依赖 clock0。所以设备之间实际上已经形成了一个图:┌──────────────┐ │ clock0 │ │ Clock Dev │ └──────▲───────┘ │ clocks │ ┌──────┴───────┐ │ uart0 │ │ UART Dev │ └──────────────┘这就是:Dependency Graph**2. phandle 到底是什么?很多人第一次看 Devicetree 会误以为:clocks=clock0;相当于:clocks=clock0;不是。Devicetree 本身并不是 C。clock0 是 Devicetree 中的:节点引用也就是:clock0 │ ▼ clock0node例如:clock0: clock@40000000这里:clock0是 label。于是:clock0就可以引用这个 node。3. 那 Zephyr 为什么需要 dependency ordinal?因为最终 C 程序需要一种方式,把:clock0node和:struct device关联起来。但是 Zephyr 不能简单地直接生成:struct device\*uart_clock=clock0_device;因为:Devicetree node 不是 C symbolnode 名字不是 C linker symbol不同 instance 可能有相同的 node nameDevicetree 是一个编译期硬件描述系统所以 Zephyr 建立了一层非常重要的映射:Devicetreenode│ ▼ dependency ordinal │ ▼ device handle │ ▼ struct device4. Dependency ordinal 是什么?可以把它简单理解成:Zephyr 给每个 Devicetree node 分配的一个内部编号。例如:clock0node↓ ordinal12uart0node↓ ordinal27那么:clock0 →12uart0 →27这个数字不是:UART 的地址也不是:IRQ number也不是:device ID而是:Zephyr Devicetree dependency graph 中的节点编号。5. 为什么需要这个编号?因为 Zephyr 最终需要把:clocks=clock0;变成某种机器可处理的信息。可以想象生成阶段得到:uart0 dependency: clock0转换成:uart0 dependency ordinal:27clock0 dependency ordinal:12然后可以进一步表达:UART0 device │ ├── dependency#12│ └──...6. Device Handle 是什么?这里就进入 Zephyr Device Model 最关键的地方。Zephyr 的:struct device并不是孤立存在的。在内部,它可以携带一组:device handles用来描述设备之间的关系。概念上可以理解成:UART0 struct device │ │ handles ▼ ┌───────────┐ │ clock0 │ └───────────┘6.1 实战:一个完整的依赖图生成示例下面用一个包含clock0、pinmux0、uart0三个节点的 DTS 文件,完整展示 Zephyr 构建系统如何为它们分配 dependency ordinal、生成 device handles,并最终映射到struct device。第一步:DTS 文件/ { soc { clock0: clock-controller@40000000 { compatible = "mycompany,my-clock"; reg = 0x40000000 0x1000; status = "okay"; }; pinmux0: pinmux@40001000 { compatible = "mycompany,my-pinmux"; reg = 0x40001000 0x1000; status = "okay"; }; uart0: serial@40002000 { compatible = "mycompany,my-uart"; reg = 0x40002000 0x1000; clocks = clock0; pinctrl-0 = pinmux0; interrupts = 10; status = "okay"; }; }; };这里uart0通过clocks = clock0和pinctrl-0 = pinmux0声明了对clock0和pinmux0的依赖。第二步:Zephyr 构建系统分配 dependency ordinalZephyr 在编译期扫描整个 Devicetree,为每个 node 分配一个全局唯一的 dependency ordinal(编号越小,依赖越靠前):clock0node→ dependency ordinal=12pinmux0node→ dependency ordinal=15uart0node→ dependency ordinal=27注意:ordinal 不是初始化优先级,它只是 Devicetree dependency graph 中的节点编号。第三步:生成 device handles每个struct device内部会携带一组 device handles,用来描述它依赖哪些设备。uart0的 device 会持有指向clock0和pinmux0的 handle:┌──────────────────────────────┐ │ uart0 struct device │ │ │ │ handles: │ │ ├──► handle#12 (clock0) ││ └──► handle#15 (pinmux0)│└──────────────────────────────┘第四步:device handles 关系图
返回列表