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

Trae搭建,AI自动帮忙配置 MCP连接sqlite数据库

Trae搭建,AI自动帮忙配置 MCP连接sqlite数据库

在这个AI浪潮席卷社会的盛况之下,与其恐惧AI,不如掌握AI。 1. Trae是什么? Trae是一款先进的AI编程助手工具,专为开发者打造。它集成在IDE中,能够理解你的代码、项目结构和编程意图,提供智能化的编码辅助功能。Trae不仅能帮助你更快地编写代码,还能提升代码质量,减少错误,大幅提高开发效率。 1)类似于deepseek这种大模型对话式的写代码 2)代码可以自动补全,通过理解上下文的代码对当前代码生成建议 3)Builder模式;从项目需求到代码、依赖、调试,Trae 都能全自动生成 4)多模态的支持:可以上传设计图,根据设计图编写代码![在这里插入图片描述](https://i-blog.ZEEKLOGimg.cn/direct/4206e784965241e6afe63267da9e312f.png) Trae分国际版和国内版本 国内版本:内置豆包 1.5 Pro 和 DeepSeek R1/V3 模型

By Ne0inhk
移动端也能玩转!OpenClaw iOS/Android 端部署教程,语音唤醒 + 全场景随身 AI 助手

移动端也能玩转!OpenClaw iOS/Android 端部署教程,语音唤醒 + 全场景随身 AI 助手

一、背景与价值:随身AI助手的刚需场景 随着大语言模型技术的普及,全场景AI助手的需求日益增长——无论是通勤途中的语音笔记、户外场景的实时翻译,还是离线环境下的知识查询,移动端随身AI都能解决传统桌面AI的场景局限。OpenClaw作为一款轻量级、可离线运行的开源AI框架,支持语音唤醒、多模态交互等核心功能,完美适配iOS/Android双平台部署,为用户打造真正的随身AI助手。 二、核心原理:OpenClaw移动端部署的技术逻辑 OpenClaw的移动端部署核心是将轻量化大语言模型(如Qwen-2-0.5B-Instruct)、语音唤醒模型(如PicoVoice Porcupine)与移动端推理引擎(如MLKit、TensorFlow Lite)进行整合,实现三大核心流程: 1. 低功耗语音唤醒:通过本地运行的轻量唤醒模型监听关键词,避免持续调用麦克风导致的高功耗; 2. 本地推理加速:利用移动端硬件加速(NNAPI、Core ML)运行量化后的大语言模型,实现离线交互; 3. 跨平台适配:通过Flutter或React Native统一代码底座,同时适配iOS的沙箱

By Ne0inhk
【AI应用开发工程师】-AI写代码总翻车?一文帮你解决(附实战案例)

【AI应用开发工程师】-AI写代码总翻车?一文帮你解决(附实战案例)

AI 写代码不按需求来?这个需求对齐 Skill 让你告别返工! 引言 你是不是也遇到过这种情况:兴冲冲地给 AI 提了个需求,结果它生成的代码完全跑偏,就像你点了一份红烧肉,端上来的却是番茄炒蛋?别急,这很可能不是 AI 的锅,而是需求没对齐!今天,我就来安利一个神器—— 需求对齐 Skill 。 目录 * 什么是需求对齐模式? * 核心原则:三大“只”字诀 * 执行流程:三步搞定需求确认 * 实际示例:视频提示词修改功能 * 如何应用这个 Skill? * 结语:一起告别返工! 什么是需求对齐模式? 简单说,这是一种让 AI“先理解,后动手”的交互模式。在没有这个 Skill 之前,每次提新需求都得和 AI“聊半天”,还经常返工。

By Ne0inhk

彻底解放AI生产力!OpenClaw + Ollama本地部署终极指南

彻底解放AI生产力!OpenClaw + Ollama本地部署终极指南 还在为天价API费用发愁?受够了网络波动导致AI服务中断?今天,零度带你解锁真正100%本地运行的AI助手解决方案!只需跟着以下步骤操作,你的电脑将变身全能AI工作站,完全免费、断网可用、多模型自由切换! 🔥 为什么选择本地部署? 三大核心优势让你无法拒绝: * 零费用:无需任何API Key,彻底告别按token计费 * 断网可用:飞机上、地下室、偏远山区照样畅快使用 * 模型自由:一键切换GPT-OSS、Qwen 3、GLM 4.7等顶尖模型 🛠️ 五分钟部署全流程 第一步:环境准备 以管理员身份打开PowerShell,依次执行: winget install git.git 若出现权限错误,追加执行: Set-ExecutionPolicy RemoteSigned -Scope CurrentUser Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass

By Ne0inhk