深入描述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.mzph.cn/diannao/60891.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LinkedHashMap实现LRU

LRU 环境&#xff1a;JDK11 最近接触LRU(Least Recently Used)&#xff0c;即最近最少使用&#xff0c;也称淘汰算法&#xff0c;在JDK中LinkedHashMap有相关实现 LRU的LinkedHashMap实现 LinkedHashMap继承HashMap。所以内存的存储结构和HashMap一样&#xff0c;但是LinkedH…

IDEA部署AI代写插件

前言 Hello大家好&#xff0c;当下是AI盛行的时代&#xff0c;好多好多东西在AI大模型的趋势下都变得非常的简单。 比如之前想画一幅风景画得先去采风&#xff0c;然后写实什么的&#xff0c;现在你只需描述出你想要的效果AI就能够根据你的描述在几分钟之内画出一幅你想要的风景…

27-压力测试

测试目标 & 测试数据 ● 测试目标 ○ 测试集群的读写性能 / 做集群容量规划 ○ 对 ES 配置参数进行修改&#xff0c;评估优化效果 ○ 修改 Mapping 和 Setting&#xff0c;对数据建模进行优化&#xff0c;并测试评估性能改进 ○ 测试 ES 新版本&#xff0c;结合实际场…

正则表达式常用字符

基础正则 ^:开头字符 $:结尾字符 ^$:空行 .:任意一个字符 *:前一个字符连续出现0次或以上 .*:所有 []&#xff1a;括号中的任意一个字符 [a-z] [a-zA-Z0-9] [a-zA-Z0-9] [^]:除括号内以外的字符 扩展正则 |:或 ssh|telnet|http ():表示整体 ^(ssh|telnet|http)^ssh|^telnet|^ht…

4. Spring Cloud Ribbon 实现“负载均衡”的详细配置说明

4. Spring Cloud Ribbon 实现“负载均衡”的详细配置说明 文章目录 4. Spring Cloud Ribbon 实现“负载均衡”的详细配置说明前言1. Ribbon 介绍1.1 LB(Load Balance 负载均衡) 2. Ribbon 原理2.2 Ribbon 机制 3. Spring Cloud Ribbon 实现负载均衡算法-应用实例4. 总结&#x…

Redis 线程模型详解:理解 Redis 高效性能的关键

Redis 是一个开源的高性能键值存储系统&#xff0c;因其卓越的速度和强大的功能被广泛应用于各种场景&#xff0c;如缓存、消息队列和实时数据存储等。Redis 的性能优越不仅归功于其高效的数据结构和内存存储&#xff0c;还源于其独特的线程模型。本文将详细介绍 Redis 的线程模…

vue3【实战】切换全屏【组件封装】FullScreen.vue

效果预览 原理解析 使用 vueUse 里的 useFullscreen() 实现 代码实现 技术方案 vue3 vite UnoCSS vueUse 组件封装 src/components/FullScreen.vue <template><component:is"tag"click"toggle":class"[!isFullscreen ? i-ep:full-sc…

docker:基于Dockerfile镜像制作完整案例

目录 摘要目录结构介绍起始目录package目录target目录sh目录init.sh脚本start.sh脚本stop.sh脚本restart.sh脚本 config目录 步骤1、编写dockerfilescript.sh脚本 2、构件镜像查看镜像 3、保存镜像到本地服务器4、复制镜像文件到指定目录&#xff0c;并执行init.sh脚本5、查看挂…

lua实现雪花算法

lua实现雪花算法 雪花算法介绍组成部分优点缺点 代码示例 雪花算法介绍 雪花算法&#xff08;Snowflake Algorithm&#xff09;是一种用于生成唯一ID的分布式生成算法&#xff0c;最初由Twitter开发。它的主要目的是在分布式系统中生成唯一的、时间有序的ID&#xff0c;这些ID通…

Spring Boot之Spring-devtools热部署

1、导包 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope> </dependency>2、添加配置 #开启热部署 spring.devtools.restart.enabledtrue #热…

STM32 | 超声波避障小车

超声波避障小车 一、项目背题 由于超声波测距是一种非接触检测技术&#xff0c;不受光线、被测对象颜色等的影响&#xff0c;较其它仪器更卫生&#xff0c;更耐潮湿、粉尘、高温、腐蚀气体等恶劣环境&#xff0c;具有少维护、不污染、高可靠、长寿命等特点。因此可广泛应用于…

第6章:TDengine 标签索引和删除数据

TDengine 标签索引和删除数据 目标 掌握标签索引的创建、删除掌握超表、子表创建以及数据删除删除数据 删除数据是 TDengine 提供的根据指定时间段删除指定表或超级表中数据记录的功能,方便用户清理由于设备故障等原因产生的异常数据。 注意:删除数据并不会立即释放该表所…

微澜:用 OceanBase 搭建基于知识图谱的实时资讯流的应用实践

本文作者&#xff1a; 北京深鉴智源科技有限公司架构师 郑荣凯 本文整理自北京深鉴智源科技有限公司架构师郑荣凯&#xff0c;在《深入浅出 OceanBase 第四期》的分享。 知识图谱是一项综合性的系统工程&#xff0c;需要在在各种应用场景中向用户展示经过分页的一度关系。 微…

多轮对话中让AI保持长期记忆的8种优化方式篇

多轮对话中让AI保持长期记忆的8种优化方式篇 一、前言 在基于大模型的 Agent 中&#xff0c;长期记忆的状态维护至关重要&#xff0c;在 OpenAI AI 应用研究主管 Lilian Weng 的博客《基于大模型的 Agent 构成》[1]中&#xff0c;将记忆视为关键的组件之一&#xff0c;下面我…

消息中间件分类

消息中间件&#xff08;Message Middleware&#xff09;是一种在分布式系统中实现跨平台、跨应用通信的软件架构。它基于消息传递机制&#xff0c;允许不同系统、不同编程语言的应用之间进行异步通信。 常见的消息中间件类型包括&#xff1a; 1. JMS&#xff08;Java Message S…

aws-athena查询语句总结

完全归于本人mysql语句小白&#xff0c;是一点也写不出来&#xff0c;故汇总到此 1. cloudtrail ## 查询事件排序 SELECT eventname,eventtime,count(eventname) as num FROM your_athena_tablename where eventtime between 2024-11-10 and 2024-11-11 group by eventname…

Swift的可选绑定(Optional binding)

在Swift中&#xff0c;有一种变量称为可选变量&#xff08;Optional&#xff09;&#xff0c;具体说明见Swift初步入门。这种变量的值可以存在也可以为空&#xff08;nil&#xff09;。在Swift中&#xff0c;可以通过将if语句和赋值语句结合&#xff0c;有条件地展开&#xff0…

关键JavaScript进行表单验证:提升用户体验与数据完整性

关键JavaScript进行表单验证&#xff1a;提升用户体验与数据完整性 在网页开发中&#xff0c;表单验证是确保用户输入有效数据的重要步骤。有效的表单验证不仅可以提高用户体验&#xff0c;还可以减少服务器端处理无效或错误数据的负担。本文将通过一个简单的示例&#xff0c;…

java集合—List常用的方法

Java集合中的List是一种有序的集合&#xff0c;可以通过索引访问元素。以下是List常用的方法&#xff1a; 添加元素&#xff1a; add(E element)&#xff1a;将指定的元素追加到列表的末尾。add(int index, E element)&#xff1a;将指定的元素插入到列表的指定位置。 获取元…

3D Gaussian Splatting 代码层理解之Part3

最后,内容到达了高斯泼溅过程中最有趣的阶段:渲染!这一步可以说是最关键的,因为它决定了模型的真实性。然而,它也可能是最简单的。在本系列的Part 1和Part2,文章演示了如何将 Raw 3D椭球 转换为可渲染的格式,但现在我们实际上必须完成这项工作并渲染到一组固定的像素上。…