ARM Linux 驱动开发篇---Linux 设备树(DTS)语法-- Ubuntu20.04

ARM Linux 驱动开发篇---Linux 设备树(DTS)语法-- Ubuntu20.04
🎬 渡水无言个人主页渡水无言

专栏传送门: 《linux专栏》   《嵌入式linux驱动开发》
⭐️流水不争先,争的是滔滔不绝

 📚博主简介:第二十届中国研究生电子设计竞赛全国二等奖 |国家奖学金 | 省级三好学生

| 省级优秀毕业生获得者 | ZEEKLOG新星杯TOP18 | 半导纵横专栏博主 | 211在读研究生

在这里主要分享自己学习的linux嵌入式领域知识;有分享错误或者不足的地方欢迎大佬指导,也欢迎各位大佬互相三连

目录

前言

一、DTS 文件的整体结构

二、.dtsi 头文件

三、设备节点

3.1、设备节点整体结构

3.2、节点命名规则

3.3节点属性

四、标准属性

4.1. compatible 属性

4.1.1、基本格式

4.2、model 属性

4.3、status 属性

4.4、#address-cells 和#size-cells 属性

4.5、reg 属性

4.6、ranges 属性

总结



前言

上一期博客我们初步介绍了一下设备树的概念,这一期博客我们来介绍一下DTS语法。


一、DTS 文件的整体结构

设备树源文件(.dts)采用一种类 C 语言的语法格式,以树形结构组织硬件信息。下面我们逐步解析其核心语法元素。

一个完整的 DTS 文件遵循树形层级结构,核心分为三部分,具体结构如下图所示:

代码如下:

// 1. 头文件/include引用(可选) #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/input/input.h> #include "imx6ull.dtsi" // 2. /dts-v1/ 版本声明(必须) /dts-v1/; // 设备树根节点,所有硬件描述都在这个节点内 / { // -------------------------- // 子节点:aliases(别名节点) // 作用:为其他节点提供简短别名,方便引用 // -------------------------- aliases { // 定义 can0 为 flexcan1 节点的别名,后续可通过 &can0 引用该CAN控制器 can0 = &flexcan1; }; // -------------------------- // 子节点:cpus(CPU集合节点) // 作用:管理系统中所有CPU核心的描述 // -------------------------- cpus { // 子节点reg属性中,地址部分占用1个32位整数 #address-cells = <1>; // 子节点reg属性中,大小部分占用0个32位整数(CPU节点不需要描述地址范围) #size-cells = <0>; // -------------------------- // 孙节点:cpu@0(CPU0核心节点) // 标签为 cpu0,方便后续引用 // -------------------------- cpu0: cpu@0 { // 兼容属性,用于内核匹配对应的CPU驱动 compatible = "arm,cortex-a7"; // 设备类型,明确该节点代表CPU设备 device_type = "cpu"; // 寄存器地址,对应CPU的ID(这里为0号CPU) reg = <0>; }; }; // -------------------------- // 子节点:interrupt-controller@00a01000(中断控制器节点) // 标签为 intc,方便后续引用 // 物理基地址为 0x00a01000 // -------------------------- intc: interrupt-controller@00a01000 { // 兼容属性,用于内核匹配对应的GIC中断控制器驱动 compatible = "arm,cortex-a7-gic"; // 引用该中断控制器时,每个中断描述占用3个32位整数 #interrupt-cells = <3>; // 标识该节点是一个中断控制器(布尔属性,存在即为真) interrupt-controller; // 寄存器地址范围,描述GIC的两个寄存器块: // 第一个块:基地址 0x00a01000,长度 0x1000 // 第二个块:基地址 0x00a02000,长度 0x100 reg = <0x00a01000 0x1000>, <0x00a02000 0x100>; }; };

二、.dtsi 头文件

和 C 语言一样,设备树也支持头文件,设备树的头文件扩展名为.dtsi。在 imx6ull-alientek-emmc.dts 中有如下所示内容:

include <dt-bindings/input/input.h> include "imx6ull.dtsi"

可以看到:

使用“#include”来引用“input.h”这个.h 头文件。

使用“#include”来引用“imx6ull.dtsi”这个.dtsi 头文件。

在.dts 设备树文件中,可以通过 “#include”来引用.h、.dtsi 和.dts 文件。只是,我们在编写设备树头文件的时候最好选择.dtsi 后缀。

一般.dtsi 文件用于描述 SOC 的内部外设信息,比如 CPU 架构、主频、外设寄存器地址范围,比如 UART、IIC 等等。比如 imx6ull.dtsi 就是描述 I.MX6ULL 这颗 SOC 内部外设情况信息的。

三、设备节点

3.1、设备节点整体结构

设备树是采用树形结构来描述板子上的设备信息的文件,每个设备都是一个节点,叫做设备节点,每个节点都通过一些属性信息来描述节点信息,属性就是键—值对。以下是从 imx6ull.dtsi 文件中缩减出来的设备树文件内容:

 // 设备树根节点,所有硬件描述都在这个节点内 / { // -------------------------- // 子节点:aliases(别名节点) // 作用:为其他节点提供简短别名,方便引用 // -------------------------- aliases { // 定义 can0 为 flexcan1 节点的别名,后续可通过 &can0 引用该CAN控制器 can0 = &flexcan1; }; // -------------------------- // 子节点:cpus(CPU集合节点) // 作用:管理系统中所有CPU核心的描述 // -------------------------- cpus { // 子节点reg属性中,地址部分占用1个32位整数 #address-cells = <1>; // 子节点reg属性中,大小部分占用0个32位整数(CPU节点不需要描述地址范围) #size-cells = <0>; // -------------------------- // 孙节点:cpu@0(CPU0核心节点) // 标签为 cpu0,方便后续引用 // -------------------------- cpu0: cpu@0 { // 兼容属性,用于内核匹配对应的CPU驱动 compatible = "arm,cortex-a7"; // 设备类型,明确该节点代表CPU设备 device_type = "cpu"; // 寄存器地址,对应CPU的ID(这里为0号CPU) reg = <0>; }; }; // -------------------------- // 子节点:interrupt-controller@00a01000(中断控制器节点) // 标签为 intc,方便后续引用 // 物理基地址为 0x00a01000 // -------------------------- intc: interrupt-controller@00a01000 { // 兼容属性,用于内核匹配对应的GIC中断控制器驱动 compatible = "arm,cortex-a7-gic"; // 引用该中断控制器时,每个中断描述占用3个32位整数 #interrupt-cells = <3>; // 标识该节点是一个中断控制器(布尔属性,存在即为真) interrupt-controller; // 寄存器地址范围,描述GIC的两个寄存器块: // 第一个块:基地址 0x00a01000,长度 0x1000 // 第二个块:基地址 0x00a02000,长度 0x100 reg = <0x00a01000 0x1000>, <0x00a02000 0x100>; }; };

“/”是根节点,每个设备树文件只有一个根节点。

注意:imx6ull.dtsi 和 imx6ull-alientek-emmc.dts 这两个文件都有一个“/”根节点,这样不会出错吗?不会的,因为这两个“/”根节点的内容会合并成一个根节点。

节点层级说明
        根节点:/ —— 整个设备树的顶层容器。
一级子节点:
        aliases:别名定义节点
        cpus:CPU 集合节点
        intc: interrupt-controller@00a01000:中断控制器节点
二级子节点(孙节点):
        cpu0: cpu@0:CPU0 核心节点,是cpus的子节点。

3.2、节点命名规则

aliases、cpus 和 intc 是三个子节点,在设备树中节点命名格式如下:

node-name@unit-address

其中“node-name”是节点名字,为 ASCII 字符串,节点名字应该能够清晰的描述出节点的功能。

“unit-address”一般表示设备的地址或寄存器首地址,如果某个节点没有地址或者寄存器的话。“unit-address”可以不要。

但是我们在3.1中的代码我们看到的节点命名却如下所示:

cpu0:cpu@0

上述命令并不是“node-name@unit-address”这样的格式,而是用“:”隔开成了两部分。“:” 前面的是节点标签(label)。“:”后面的才是节点名字。格式如下所示:

label: node-name@unit-address

引入 label 的目的就是为了方便访问节点,可以直接通过&label 来访问这个节点,比如通过&cpu0 就可以访问“cpu@0”这个节点,而不需要输入完整的节点名字。

3.3节点属性

每个节点都有不同属性,不同的属性又有不同的内容,属性都是键值对,值可以为空或任意的字节流。设备树源码中常用的几种数据形式如下所示:

①、字符串

compatible = "arm,cortex-a7";

上述代码设置 compatible 属性的值为字符串“arm,cortex-a7”。

②、32 位无符号整数

reg = <0>;

上述代码设置 reg 属性的值为 0,reg 的值也可以设置为一组值,比如:

reg = <0 0x123456 100>;

③、字符串列表

属性值也可以为字符串列表,字符串和字符串之间采用“,”隔开,如下所示:

compatible = "fsl,imx6ull-gpmi-nand", "fsl, imx6ul-gpmi-nand";

上述代码设置属性 compatible 的值为“fsl,imx6ull-gpmi-nand”和“fsl, imx6ul-gpmi-nand”。

四、标准属性

节点是由一堆的属性组成,节点都是具体的设备,不同的设备需要的属性不同,用户可以自定义属性。除了用户自定义属性,有很多属性是标准属性,Linux 下的很多外设驱动都会使用这些标准属性,本节我们就来学习一下几个常用的标准属性。

4.1. compatible 属性

compatible 属性是设备树中最核心、最重要的标准属性,没有之一!它也被称为 “兼容性属性”,核心作用是将硬件设备节点与 Linux 内核中的驱动程序完成绑定匹配。

4.1.1、基本格式

compatible 属性的值是一个字符串列表,每个字符串都遵循统一的命名规范:

compatible = "manufacturer,model";

manufacturer:设备厂商标识(如 fsl 代表飞思卡尔、rockchip 代表瑞芯微);
model:设备型号 / 对应的驱动模块名称,内核会通过该字段匹配具体驱动。

例子:

compatible = "fsl,imx6ul-evk-wm8960","fsl,imx-audio-wm8960";

该属性包含两个兼容值,内核会按顺序匹配:
优先使用第一个值 fsl,imx6ul-evk-wm8960 在内核中查找匹配的驱动;
若未找到,则使用第二个值 fsl,imx-audio-wm8960 继续查找。

这种 “多值列表” 的设计,既可以适配专属驱动,也能兼容通用驱动,是设备树兼容性设计的核心思路。

一般驱动程序文件都会有一个 OF 匹配表,此 OF 匹配表保存着一些 compatible 值,如果设备节点的 compatible 属性值和 OF 匹配表中的任何一个值相等,那么就表示设备可以使用这个驱动。

4.2、model 属性

model 属性值也是一个字符串,一般 model 属性描述设备模块信息,比如名字什么的,比如:

model = "wm8960-audio";

4.3、status 属性

status 属性看名字就知道是和设备状态有关的,status 属性值也是字符串,字符串是设备的状态信息,可选的状态如表所示:

描述
"okay"表明设备是可操作的。
"disabled"表明设备当前是不可操作的,但在未来可以变为可操作的(如热插拔设备插入后)。具体含义还要看设备的绑定文档。
"fail"表明设备不可操作,设备检测到了一系列的错误,而且设备也不大可能变得可操作。
"fail-sss"含义和 "fail" 相同,后面的 sss 部分是检测到的错误内容。

4.4、#address-cells 和#size-cells 属性

#address-cells#size-cells 是设备树中用于描述子节点地址信息的关键属性,它们的值均为无符号 32 位整数。这两个属性可以作用于任何拥有子节点的设备节点,用于规范其子节点 reg 属性的格式。

核心作用

#address-cells:决定子节点 reg 属性中,起始地址(address) 部分所占用的 32 位字长。
#size-cells:决定子节点 reg 属性中,地址长度(length) 部分所占用的 32 位字长。

#address-cells 和#size-cells 表明了子节点应该如何编写 reg 属性值,一般 reg 属性

都是和地址有关的内容,和地址相关的信息有两种:起始地址和地址长度,reg 属性的格式一为:

reg = <address1 length1 address2 length2 address3 length3……>

每个“address length”组合表示一个地址范围,其中 address 是起始地址,length 是地址长

度,#address-cells 表明 address 这个数据所占用的字长,#size-cells 表明 length 这个数据所占用

的字长,比如:

aips3: aips-bus@02200000 { compatible = "fsl,aips-bus", "simple-bus"; #address-cells = <1>; // 子节点地址占1个32位字 #size-cells = <1>; // 子节点长度占1个32位字 dcp: dcp@02280000 { compatible = "fsl,imx6sl-dcp"; reg = <0x02280000 0x4000>; // 地址: 0x02280000, 长度: 0x4000 }; };

子节点 dcp@02280000 的 reg = <0x02280000 0x4000> 严格遵循了这一规则,清晰地定义了该设备的寄存器基地址为 0x02280000,地址空间大小为 0x4000 字节。

4.5、reg 属性

reg 属性前面已经提到过了,reg 属性的值一般是(address,length)对。reg 属性一般用于描述设备地址空间资源信息,一般都是某个外设的寄存器地址范围信息。

4.6、ranges 属性

ranges 是设备树中用于描述子总线与父总线地址映射关系的标准属性,核心作用是实现地址空间的转换或映射。该属性的值有两种形式:
        空值(ranges;):表示子总线地址空间与父总线地址空间完全一致,无需做地址转换;
        数字矩阵:按 (child-bus-address, parent-bus-address, length) 格式编写,每一组数据对应一段地址映射关系。

ranges 属性的每一组映射关系包含三个核心参数,其字长由父节点#address-cells#size-cells 决定:

参数

含义

字长规则

child-bus-address

子总线地址空间的起始物理地址

由父节点 #address-cells 定义

parent-bus-address

父总线地址空间的起始物理地址(子地址要映射到的目标地址)

由父节点 #address-cells 定义

length

本次映射的地址空间长度(子地址空间的有效范围)

由父节点 #size-cells 定义

总结

本期博客主要介绍了DTS的语法情况

Read more

前端异常捕获与统一格式化:从 console.log(error) 到服务端上报

前端异常捕获与统一格式化:从 console.log(error) 到服务端上报

🧑 博主简介:ZEEKLOG博客专家,「历代文学网」(公益文学网,PC端可以访问:https://lidaiwenxue.com/#/?__c=1000,移动端可关注公众号 “ 心海云图 ” 微信小程序搜索“历代文学”)总架构师,首席架构师,也是联合创始人!16年工作经验,精通Java编程,高并发设计,分布式系统架构设计,Springboot和微服务,熟悉Linux,ESXI虚拟化以及云原生Docker和K8s,热衷于探索科技的边界,并将理论知识转化为实际应用。保持对新技术的好奇心,乐于分享所学,希望通过我的实践经历和见解,启发他人的创新思维。在这里,我希望能与志同道合的朋友交流探讨,共同进步,一起在技术的世界里不断学习成长。 🤝商务合作:请搜索或扫码关注微信公众号 “ 心海云图 ” 前端异常捕获与统一格式化:从 console.log(error) 到服务端上报 引言 在前端开发中,异常监控是保证应用稳定性的重要一环。当用户遇到页面白屏、功能不可用等问题时,如果能及时收集到详细的错误信息(包括堆栈、

By Ne0inhk
【AI深究】逻辑回归(Logistic Regression)全网最详细全流程详解与案例(附大量Python代码演示)| 数学原理、案例流程、代码演示及结果解读 | 决策边界、正则化、优缺点及工程建议

【AI深究】逻辑回归(Logistic Regression)全网最详细全流程详解与案例(附大量Python代码演示)| 数学原理、案例流程、代码演示及结果解读 | 决策边界、正则化、优缺点及工程建议

大家好,我是爱酱。本篇将系统讲解——逻辑回归(Logistic Regression)的原理、公式、案例流程、代码实现和工程建议。内容详细分步,便于新手和进阶读者理解和实操。 注:本文章含大量数学算式、详细例子说明及大量代码演示,大量干货,建议先收藏再慢慢观看理解。新频道发展不易,你们的每个赞、收藏跟转发都是我继续分享的动力! 注:本文章颇长近5000字、以及大量Python代码、非常耗时制作,建议先收藏再慢慢观看。新频道发展不易,你们的每个赞、收藏跟转发都是我继续分享的动力! 一、逻辑回归简介 逻辑回归是一种经典的线性分类算法,本质上是用Sigmoid函数将线性回归的输出“压缩”到0~1之间,输出为概率,常用于二分类任务。 与KNN(K-近邻算法)不同,逻辑回归是判别式模型,直接建模输入特征与类别之间的概率关系,适合特征和类别呈线性可分或近似线性关系的数据。 注:爱酱也有文章介绍了分类以及其他五大任务的技巧,有兴趣的也可以参考一下哦~ 分类任务文章传送门: 【算法解析1/5】分类任务深度拆解:

By Ne0inhk
用AI给老照片上色:算法对比与调参技巧

用AI给老照片上色:算法对比与调参技巧

用AI给老照片上色:算法对比与调参技巧 * 一、前言 * 二、传统上色算法与局限性 * 2.1 基于直方图匹配的上色算法 * 2.2 基于特征匹配的上色算法 * 三、基于深度学习的上色算法 * 3.1 基于 CNN 的端到端上色算法 * 3.2 基于 GAN 的上色算法 * 3.3 基于Transformer的上色算法 * 四、实用调参技巧 * 4.1 数据预处理调参 * 4.1.1 图像分辨率调整 * 5.1.2 降噪与增强参数 * 5.2 模型结构调参 * 5.2.1 CNN 模型调参 * 5.2.

By Ne0inhk
【数据结构指南】高频二叉树节点问题

【数据结构指南】高频二叉树节点问题

前言:               在熟练掌握二叉树四种基本遍历方法的基础上,本文将深入探讨以下进阶问题:节点总数统计、叶子节点计算、第k层节点数量确定、节点的查找以及树高测量。         这些内容将帮助读者深化对二叉树结构的理解与应用能力,以及深入理解递归分治思想。            一、前置说明:          本文所描述的二叉树都是链式二叉树,其定义方式如下所示:          typedef char BTDataType; typedef struct BinaryTree { BTDataType data; struct BinaryTree* left; struct BinaryTree* right; }BTNode;          二、二叉树的创建及销毁          通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树,其中'#'表示该节点为NULL,二叉树如下图所示:                   前序遍历的思想为: 先访问根节点  ->  再访问左子树 -&

By Ne0inhk