当前位置: 首页 > news >正文

深入描述dts和dtsi的区别

QA:dts和dtsi的区别

在嵌入式 Linux 系统中,DTS(Device Tree Source)和 DTSI(Device Tree Source Include)是描述硬件设备树的文件格式。它们本质上是同一种语法的文件,但在使用上有一定区别。以下是两者的主要差异和用途:

1. 文件类型和用途

  • DTS (Device Tree Source)
    DTS 文件是设备树的主文件,描述了一个具体设备或板子的硬件配置。每个具体的硬件设备都会有一个对应的 DTS 文件,它是系统用来解析设备硬件结构的主要输入。
    例如:board.dts

  • DTSI (Device Tree Source Include)
    DTSI 文件是设备树的包含文件,通常是一个共享的硬件描述片段,供多个 DTS 文件引用。DTSI 文件中定义的是通用或模块化的硬件配置,目的是实现代码复用。
    例如:chip.dtsi


2. 内容层次

  • DTS
    通常定义特定板级硬件相关的配置,例如 GPIO 引脚分配、外设启用等。

    /dts-v1/;
    /include/ "chip.dtsi"/ {model = "Custom Board";compatible = "custom,board";aliases {serial0 = &uart0;};chosen {stdout-path = &uart0;};
    };

  • DTSI
    通常定义 SoC(芯片)级或通用硬件部分的配置,适用于多个设备树文件。

    /dts-v1/;/ {soc {uart0: serial@10000000 {compatible = "ns16550";reg = <0x10000000 0x1000>;clock-frequency = <24000000>;};};
    };


3. 继承和覆盖

DTS 文件通过 /include/ 指令包含 DTSI 文件中的内容,然后可以覆盖其中的属性。

例如:

  • 在 chip.dtsi 中定义了 UART 外设;
  • 在 board.dts 中可以基于 chip.dtsi,启用或修改 UART 的配置。
继承示例

chip.dtsi:

/include/ "chip.dtsi"&uart0 {status = "okay"; // 覆盖为启用
};

board.dts:

/include/ "chip.dtsi"&uart0 {status = "okay"; // 覆盖为启用
};

4. 文件组织

  • DTSI 通常由芯片厂商或 SoC 开发人员提供,用于定义通用部分,例如 CPU、外设等。
  • DTS 通常由板级开发人员创建,用于描述特定开发板或产品的具体硬件配置。

5. 总结对比

属性DTSDTSI
用途定义具体设备或板级配置定义共享或通用硬件配置
作用具体化设备树描述模块化、复用
包含关系可引用多个 DTSI 文件通常不引用其他文件
适用范围针对单个设备/板子针对芯片级或通用配置

通过这种分层结构,可以实现设备树文件的模块化和复用,从而简化开发和维护工作。

QA:如果我是板级工程师,那么我不应该修改dtsi文件,而是只能新增或者修改dts文件?

是的,作为板级工程师,一般不建议直接修改 DTSI 文件,而是通过新增或修改 DTS 文件来完成硬件描述。这样做的原因如下:


为什么不建议修改 DTSI 文件?

  1. DTSI 文件通常由芯片厂商或 BSP 提供

    • DTSI 文件一般描述的是芯片级(SoC 级)的硬件资源和特性,这些内容是通用的,适用于多种不同的开发板或设备。修改 DTSI 可能会影响其他使用相同芯片的项目。
    • 如果您修改了 DTSI 文件,在后续升级厂商提供的 BSP(Board Support Package)时,可能会导致冲突,甚至丢失修改内容。
  2. 分层设计的目的

    • DTSI 文件的作用是描述通用硬件资源,而 DTS 文件是为具体板级定制的。通过继承和覆盖,可以避免直接修改通用内容,从而维护良好的分层结构。
  3. 方便维护和协作

    • 当多个工程师协作开发时,如果每个人都能随意修改 DTSI 文件,会导致难以追踪改动来源,增加协作复杂度。
    • 如果只修改 DTS 文件,改动是板级特有的,容易维护和调试。

正确的做法:通过 DTS 文件实现定制化

如果需要在板级启用或修改某些硬件资源,可以在 DTS 文件中通过继承和覆盖的方式实现。以下是常见情况的处理方式:

1. 启用某些外设

DTSI 文件中通常将外设状态设置为 "disabled",您可以在 DTS 文件中将其改为 "okay"

/include/ "chip.dtsi"&uart0 {status = "okay";  // 启用 UART0pinctrl-names = "default";pinctrl-0 = <&uart0_pins>;
};

2. 添加板级特有的外设

如果板子上有芯片厂商未定义的外设,比如额外的传感器或定制模块,可以直接在 DTS 文件中新增节点,而无需修改 DTSI 文件。

&i2c1 {status = "okay";temp_sensor@48 {compatible = "mycompany,temp-sensor";reg = <0x48>;};
};

3. 覆盖特定配置

如果板级需要调整某些硬件资源(例如 GPIO 引脚或时钟频率),可以在 DTS 中覆盖 DTSI 的默认配置:

&spi0 {status = "okay";cs-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>;  // 修改片选引脚
};

如果修改 DTSI 是必需的情况

尽管一般不建议修改 DTSI 文件,但在以下情况下,可以考虑调整:

  1. 厂商提供的 DTSI 文件存在错误

    如果您确认芯片厂商的 DTSI 文件有问题(如硬件地址或属性错误),可以修复后在项目内使用。
  2. 特定项目的定制需求

    如果您确定该 DTSI 文件仅用于当前项目,且不会影响其他设备或板子,可以直接修改,但需要清楚记录原因。
  3. 实验性调试

    如果某些问题需要快速验证,您可以临时修改 DTSI,但在正式实现时应将更改移到 DTS 文件中。

总结建议

  • 优先修改 DTS 文件:通过覆盖或新增节点实现板级定制。
  • 尽量避免修改 DTSI 文件:保持芯片级硬件描述的通用性。
  • 如需修改 DTSI 文件:确保原因充分,并明确记录,以便后续维护。

通过这种方式,可以既满足项目需求,又维持代码的模块化和可维护性。

 QA:有人说dts和dtsi的关系就像.c文件和.h文件的include关系。这样的说法准确吗?

网上将 DTS 和 DTSI 的关系类比为 .c 文件和 .h 文件的关系,并不完全准确。这种类比可能有助于初学者快速理解它们的引用方式,但实际上两者的作用和结构存在显著差异。


为什么类比不准确?

1. .h 文件与 .c 文件的分工明确
  • .h 文件:主要是接口声明,定义函数、变量或结构体的原型。它不包含具体实现。
  • .c 文件:主要是实现具体功能,编写函数的逻辑代码。

这种分工明确的方式在 DTS 和 DTSI 中并不存在,因为 DTSI 文件不仅包含“声明”内容,还包含许多具体配置(属性和硬件节点),可以直接被系统解析和使用。

2. DTSI 文件包含具体实现

DTSI 文件并不是简单的“声明文件”,而是包含大量具体硬件配置。例如:

uart0: serial@10000000 {compatible = "ns16550";reg = <0x10000000 0x1000>;clock-frequency = <24000000>;status = "disabled";
};

以上代码实际上已经定义了 UART 的硬件地址、寄存器大小和时钟频率,这些是完整的硬件描述,直接参与设备树解析,并非简单的“接口声明”。

3. DTS 和 DTSI 的关系是“继承与覆盖”

DTS 文件从 DTSI 文件中“继承”节点配置,并可以通过覆盖来调整具体的属性值。这种行为更接近面向对象编程中的“继承”关系,而不是简单的“引用”关系。


更贴切的类比是什么?

将 DTSI 比作一个“父类”或“模板”,将 DTS 比作一个“子类”可能更恰当:

  1. DTSI 定义了通用的硬件节点和默认配置,相当于父类提供的通用功能和默认属性。
  2. DTS 则在继承 DTSI 内容的基础上,进一步细化或修改配置,相当于子类对父类进行扩展或覆盖。
示例(继承与覆盖关系)
// chip.dtsi
soc {uart0: serial@10000000 {compatible = "ns16550";reg = <0x10000000 0x1000>;clock-frequency = <24000000>;status = "disabled";  // 默认禁用};
};
// board.dts
/include/ "chip.dtsi"&uart0 {status = "okay";  // 覆盖为启用
};

在这个例子中:

  • chip.dtsi 定义了通用的 UART 硬件节点和属性;
  • board.dts 继承了 chip.dtsi 中的内容,并根据具体板级需求调整状态。

总结:为什么网上的类比有局限性?

  • DTSI 文件不仅仅是“声明”性质,它包含具体实现,而 .h 文件不包含实现。
  • DTS 文件不是从零开始实现所有功能,而是基于 DTSI 的内容进行扩展或覆盖。
  • 它们的关系更接近“模板(父类)”与“实例(子类)”,而不是“接口与实现”。

因此,用 继承与覆盖 来描述 DTS 和 DTSI 的关系,比简单的 .c 和 .h 文件类比更准确,也更符合设备树的实际用法。

http://www.lryc.cn/news/485918.html

相关文章:

  • 京准时钟:一种北斗卫星校时器的结构设计
  • 【WiFi】ubuntu20.4 WiFi6 无线抓包环境搭建及使用
  • 《Java核心技术 卷I》用户界面AWT事件继承层次
  • 蓝牙 HFP 协议详解及 Android 实现
  • sqli-labs靶场17-20关(每日四关)持续更新!!!
  • 动态规划-完全背包问题——518.零钱兑换II
  • [模板总结] - 单向链表LinkedList操作
  • fastadmin多个表crud连表操作步骤
  • 山西省网络建设与运维第十八届职业院校技能大赛(样题)
  • 服务端高并发分布式结构进阶之路
  • 分布式微服务项目,同一个controller不同方法间的转发导致cookie丢失,报错null pointer异常
  • STM32 ADC --- 任意单通道采样
  • vscode中执行git合并操作需要输入合并commit信息,打开的nano小型文本编辑器说明-
  • 蓝桥杯每日真题 - 第7天
  • 【Git】Git Clone 指定自定义文件夹名称:详尽指南
  • 终端快捷键学习笔记
  • Go语言24小时极速学习教程(四)MySQL数据库的增删改查
  • 04 - Clickhouse-21.7.3.14-2单机版安装
  • 多项式回归
  • vscode报错:Connecting with SSH time-out.
  • python可视化将多张图整合到一起(画布)
  • C函数如何返回参数lua使用
  • pytest在conftest.py中实现用例执行失败进行截图并附到allure测试报告
  • 编程之路,从0开始:数据在内存中的存储
  • 二叉树+树的OJ题讲解
  • 信捷PLC转以太网连接电脑方法
  • 释放 PWA 的力量:2024 年的现代Web应用|React + TypeScript 示例
  • CVSS4与CVSS3的不同之二
  • 【Pip】如何清理 `pip` 包管理器 —— 完整指南
  • 操作数据库