ARM Linux 驱动开发篇---Linux设备树实战-- Ubuntu20.04

🎬 渡水无言个人主页渡水无言

专栏传送门 : 《linux专栏》《嵌入式linux驱动开发》

⭐️流水不争先,争的是滔滔不绝

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

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

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

目录

前言

一、向节点追加或修改内容

1.1、直接修改imx6ull.dtsi文件的弊端

[1.2、正确方案:通过 & label 向节点追加 / 修改内容](#1.2、正确方案:通过 & label 向节点追加 / 修改内容)

二、创建小型模板设备树

[2.1、编写目标:描述 I.MX6ULL 核心硬件](#2.1、编写目标:描述 I.MX6ULL 核心硬件)

2.2、分步编写:从框架到完整设备树

[2.3、步骤 1:搭建根节点基础框架](#2.3、步骤 1:搭建根节点基础框架)

[2.4、步骤 2:添加 CPU 节点(描述核心处理器)](#2.4、步骤 2:添加 CPU 节点(描述核心处理器))

[2.5、步骤 3:添加 SOC 节点(管理内部外设)](#2.5、步骤 3:添加 SOC 节点(管理内部外设))

[2.6、步骤 4:添加 OCRAM 节点(描述内部 RAM)](#2.6、步骤 4:添加 OCRAM 节点(描述内部 RAM))

[2.7、步骤 5:添加 AIPS1/AIPS2/AIPS3 总线域节点](#2.7、步骤 5:添加 AIPS1/AIPS2/AIPS3 总线域节点)

[2.7、步骤 6:添加外设控制器节点(ECSPI1/USBOTG1/RNGB)](#2.7、步骤 6:添加外设控制器节点(ECSPI1/USBOTG1/RNGB))

总结


前言

前一期博客我们介绍了设备树的语法,这一期博客我们再介绍一下如何向节点追加或修改内容,以及尝试创建一个小型的模板设备树。


一、向节点追加或修改内容

在嵌入式产品开发中,硬件需求变更十分常见设备树作为硬件描述文件,必须同步适配硬件修改。本次博客以 I.MX6U-ALPHA 开发板为例,介绍如何向已有 I2C1 节点追加 fxls8471 子节点,同时保证修改仅作用于当前开发板,不影响其他基于 I.MX6ULL 的板子。

1.1、直接修改imx6ull.dtsi文件的弊端

首先看 I.MX6ULL 的 I2C1 节点定义(位于imx6ull.dtsi文件中),这是所有基于 I.MX6ULL 的板子都会引用的通用设备树头文件:

复制代码
i2c1: i2c@021a0000 {
    #address-cells = <1>;
    #size-cells = <0>;
    compatible = "fsl,imx6ul-i2c", "fsl,imx21-i2c";
    reg = <0x021a0000 0x4000>;
    interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&clks IMX6UL_CLK_I2C1>;
    status = "disabled"; // 默认禁用I2C1
};

如果直接在imx6ull.dtsi的 i2c1 节点下添加 fxls8471 子节点(如下所示),会导致所有引用该 DTSI 的板子都被强制添加这个设备 ,这明显不合理啊!

复制代码
// 错误示范:直接修改通用DTSI文件
i2c1: i2c@021a0000 {
    #address-cells = <1>;
    #size-cells = <0>;
    compatible = "fsl,imx6ul-i2c", "fsl,imx21-i2c";
    reg = <0x021a0000 0x4000>;
    interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&clks IMX6UL_CLK_I2C1>;
    status = "disabled";

    // 直接添加会影响所有板子
    fxls8471@1e {
        compatible = "fsl,fxls8471";
        reg = <0x1e>;
    };
};

这里就要引入另外一个内容,那就是如何向节点追加数据,我们现在要解决的就是如何向 i2c1 节点追加一个名为 fxls8471 的子节点,而且不能影响到其他使用到 I.MX6ULL 的板子。

1.2、正确方案:通过 & label 向节点追加 / 修改内容

I.MX6U-ALPHA 开发板有专属的设备树文件imx6ull-alientek-emmc.dts,我们需要在这个文件中通过节点标签引用(&label) 的方式,仅对当前板子的 i2c1 节点做修改,核心语法如下:

复制代码
&节点标签 {
    // 要追加的子节点/要修改的属性
};

&节点标签:通过节点的 label(如i2c1)定位到imx6ull.dtsi中的目标节点,无需写完整节点路径;

花括号内:可新增属性、修改原有属性值、添加子节点,且所有修改仅作用于当前 DTS 文件对应的板子。

以下是imx6ull-alientek-emmc.dts中对 i2c1 节点的完整修改示例,兼顾 "启用 I2C1""配置参数""追加子节点" 三大需求:

复制代码
&i2c1 {
    // 1. 新增属性:配置I2C1时钟频率为100KHz
    clock-frequency = <100000>;
    // 2. 配置I2C1引脚复用
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_i2c1>;
    // 3. 修改原有属性:启用I2C1(覆盖dtsi中的disabled)
    status = "okay";

    // 4. 追加子节点:mag3110磁力计(NXP官方板配置,可根据实际硬件删除)
    mag3110@0e {
        compatible = "fsl,mag3110";
        reg = <0x0e>; // I2C设备地址0x0e
        position = <2>;
    };

    // 5. 追加子节点:fxls8471六轴芯片(核心需求)
    fxls8471@1e {
        compatible = "fsl,fxls8471";
        reg = <0x1e>; // I2C设备地址0x1e
        position = <0>;
        // 配置中断引脚:挂载到GPIO5的第0引脚,触发方式为高电平(8对应IRQ_TYPE_LEVEL_HIGH)
        interrupt-parent = <&gpio5>;
        interrupts = <0 8>;
    };
};

属性修改优先级:DTS 文件中通过&label修改的属性(如status = "okay"),会覆盖 DTSI 文件中该节点的原有属性值;

子节点作用域:追加的子节点(如 fxls8471@1e)仅存在于当前开发板的设备树中,不会影响其他引用imx6ull.dtsi的板子;

二、创建小型模板设备树

上一期博客我们详细讲解了DTS的核心语法规则,本节将通过从零编写一个极简版 I.MX6ULL 设备树文件,这个设备树仅用于语法练习(无实际运行意义);实际产品开发中,我们无需从零写.dts 文件,只需基于 SOC 厂商提供的.dts/.dtsi 文件做定制化修改即可。

2.1、编写目标:描述 I.MX6ULL 核心硬件

我们需要在设备树中描述 I.MX6ULL 的 5 类核心硬件,覆盖 CPU、内部 RAM、外设控制器等关键组件:

  1. Cortex-A7 架构的 32 位 CPU(单核心);

  2. 内部 OCRAM:起始地址0x00900000,大小 128KB(0x20000);

  3. AIPS1 域下 ECSPI1 控制器:寄存器起始地址0x02008000,大小0x4000

  4. AIPS2 域下 USBOTG1 控制器:寄存器起始地址0x02184000,大小0x4000

  5. AIPS3 域下 RNGB 控制器:寄存器起始地址0x02284000,大小0x4000

2.2、分步编写:从框架到完整设备树

新建myfirst.dts文件,按 "基础框架→CPU→SOC→内存→总线域→外设" 的顺序逐步完善。

2.3、步骤 1:搭建根节点基础框架

设备树的核心是根节点/,先搭建最基础的根节点框架,仅包含兼容属性:

复制代码
// myfirst.dts - 基础框架
/ {
    // 兼容属性:标识板子和SOC型号
    compatible = "fsl,imx6ull-alientek-evk", "fsl,imx6ull";
};

2.4、步骤 2:添加 CPU 节点(描述核心处理器)

I.MX6ULL 是单核心 Cortex-A7,需创建cpus父节点管理 CPU 子节点,核心规则:

#address-cells = <1>:CPU 地址占 1 个 32 位字长;

#size-cells = <0>:CPU 无地址长度(仅需标识核心 ID);

device_type = "cpu":明确节点类型为 CPU。

复制代码
/ {
    compatible = "fsl,imx6ull-alientek-evk", "fsl,imx6ull";

    // CPU集合节点:管理所有CPU核心
    cpus {
        #address-cells = <1>;
        #size-cells = <0>;

        // CPU0子节点:描述唯一的Cortex-A7核心
        cpu0: cpu@0 {
            compatible = "arm,cortex-a7"; // 匹配Cortex-A7驱动
            device_type = "cpu";         // 标识为CPU设备
            reg = <0>;                   // CPU核心ID为0
        };
    };
};

2.5、步骤 3:添加 SOC 节点(管理内部外设)

I.MX6ULL 的 UART、I2C、SPI 等外设均属于 SOC 内部资源,需创建soc父节点统一管理,核心配置:

#address-cells = <1>/#size-cells = <1>:子节点 reg 属性为 "1 个地址 + 1 个长度";

compatible = "simple-bus":标识为简单总线(通用总线类型);

ranges;:空值表示子地址空间与父地址空间一致,无需地址转换。

复制代码
/ {
    compatible = "fsl,imx6ull-alientek-evk", "fsl,imx6ull";

    cpus {
        #address-cells = <1>;
        #size-cells = <0>;
        cpu0: cpu@0 {
            compatible = "arm,cortex-a7";
            device_type = "cpu";
            reg = <0>;
        };
    };

    // SOC节点:管理所有内部外设
    soc {
        #address-cells = <1>;
        #size-cells = <1>;
        compatible = "simple-bus";
        ranges; // 子地址=父地址,无需转换
    };
};

2.6、步骤 4:添加 OCRAM 节点(描述内部 RAM)

OCRAM 是 I.MX6ULL 的内部 SRAM,属于 SOC 子节点,核心配置:

节点命名:sram@00900000(类型 + 起始地址)。

reg属性:<起始地址 大小>,即<0x00900000 0x20000>。

复制代码
/ {
    compatible = "fsl,imx6ull-alientek-evk", "fsl,imx6ull";

    cpus {
        #address-cells = <1>;
        #size-cells = <0>;
        cpu0: cpu@0 {
            compatible = "arm,cortex-a7";
            device_type = "cpu";
            reg = <0>;
        };
    };

    soc {
        #address-cells = <1>;
        #size-cells = <1>;
        compatible = "simple-bus";
        ranges;

        // OCRAM节点:内部SRAM
        ocram: sram@00900000 {
            compatible = "fsl,lpm-sram"; // 匹配NXP低功耗SRAM驱动
            reg = <0x00900000 0x20000>;  // 起始地址+大小
        };
    };
};

2.7、步骤 5:添加 AIPS1/AIPS2/AIPS3 总线域节点

I.MX6ULL 的外设分为 3 个 AIPS 总线域,每个域对应独立的地址空间,地址范围如下:

复制代码
总线域	起始地址	大小
AIPS1	0x02000000	0x100000
AIPS2	0x02100000	0x100000
AIPS3	0x02200000	0x100000

每个 AIPS 节点需配置:

compatible = "fsl,aips-bus", "simple-bus":匹配 NXP AIPS 总线驱动;

reg属性:总线域的地址范围;

ranges;:子地址与父地址一致。

复制代码
/ {
    compatible = "fsl,imx6ull-alientek-evk", "fsl,imx6ull";

    cpus {
        #address-cells = <1>;
        #size-cells = <0>;
        cpu0: cpu@0 {
            compatible = "arm,cortex-a7";
            device_type = "cpu";
            reg = <0>;
        };
    };

    soc {
        #address-cells = <1>;
        #size-cells = <1>;
        compatible = "simple-bus";
        ranges;

        ocram: sram@00900000 {
            compatible = "fsl,lpm-sram";
            reg = <0x00900000 0x20000>;
        };

        // AIPS1总线域:管理ECSPI1等外设
        aips1: aips-bus@02000000 {
            compatible = "fsl,aips-bus", "simple-bus";
            #address-cells = <1>;
            #size-cells = <1>;
            reg = <0x02000000 0x100000>;
            ranges;
        };

        // AIPS2总线域:管理USBOTG1等外设
        aips2: aips-bus@02100000 {
            compatible = "fsl,aips-bus", "simple-bus";
            #address-cells = <1>;
            #size-cells = <1>;
            reg = <0x02100000 0x100000>;
            ranges;
        };

        // AIPS3总线域:管理RNGB等外设
        aips3: aips-bus@02200000 {
            compatible = "fsl,aips-bus", "simple-bus";
            #address-cells = <1>;
            #size-cells = <1>;
            reg = <0x02200000 0x100000>;
            ranges;
        };
    };
};

2.7、步骤 6:添加外设控制器节点(ECSPI1/USBOTG1/RNGB)

最后在对应 AIPS 域下添加外设控制器节点,核心规则:

ECSPI1 属于 AIPS1,USBOTG1 属于 AIPS2,RNGB 属于 AIPS3;

reg属性:外设寄存器的起始地址 + 大小;

status = "disabled":默认禁用(实际开发中可改为okay启用)。

复制代码
// myfirst.dts - 完整的I.MX6ULL极简设备树
/dts-v1/; // 补充DTS版本声明(规范要求)

/ {
    compatible = "fsl,imx6ull-alientek-evk", "fsl,imx6ull";

    // CPU核心描述
    cpus {
        #address-cells = <1>;
        #size-cells = <0>;
        cpu0: cpu@0 {
            compatible = "arm,cortex-a7";
            device_type = "cpu";
            reg = <0>;
        };
    };

    // SOC内部外设总节点
    soc {
        #address-cells = <1>;
        #size-cells = <1>;
        compatible = "simple-bus";
        ranges;

        // 内部OCRAM
        ocram: sram@00900000 {
            compatible = "fsl,lpm-sram";
            reg = <0x00900000 0x20000>;
        };

        // AIPS1域 + ECSPI1控制器
        aips1: aips-bus@02000000 {
            compatible = "fsl,aips-bus", "simple-bus";
            #address-cells = <1>;
            #size-cells = <1>;
            reg = <0x02000000 0x100000>;
            ranges;

            ecspi1: ecspi@02008000 {
                #address-cells = <1>;
                #size-cells = <0>;
                compatible = "fsl,imx6ul-ecspi", "fsl,imx51-ecspi";
                reg = <0x02008000 0x4000>;
                status = "disabled"; // 默认禁用
            };
        };

        // AIPS2域 + USBOTG1控制器
        aips2: aips-bus@02100000 {
            compatible = "fsl,aips-bus", "simple-bus";
            #address-cells = <1>;
            #size-cells = <1>;
            reg = <0x02100000 0x100000>;
            ranges;

            usbotg1: usb@02184000 {
                compatible = "fsl,imx6ul-usb", "fsl,imx27-usb";
                reg = <0x02184000 0x4000>;
                status = "disabled"; // 默认禁用
            };
        };

        // AIPS3域 + RNGB控制器
        aips3: aips-bus@02200000 {
            compatible = "fsl,aips-bus", "simple-bus";
            #address-cells = <1>;
            #size-cells = <1>;
            reg = <0x02200000 0x100000>;
            ranges;

            rngb: rngb@02284000 {
                compatible = "fsl,imx6sl-rng", "fsl,imx-rng", "imx-rng";
                reg = <0x02284000 0x4000>;
            };
        };
    };
};

至此,myfirst.dts 这个小型的模板设备树就编写好了,基本和 imx6ull.dtsi 很像,可以看做是 imx6ull.dtsi 的缩小版。


总结

这一期博客我们介绍了如何向节点追加或修改内容,以及尝试创建一个小型的模板设备树。

相关推荐
Chasing Aurora1 小时前
vscode连接 服务器进行 深度学习
linux·ide·vscode·深度学习·研究生·解压缩·连接服务器
未名编程1 小时前
Linux / macOS / Windows 一条命令安装 Node.js + npm(极限一行版大全)
linux·macos·node.js
哈哈浩丶2 小时前
LK(little kernel)-3:LK的启动流程-作为Android的bootloarder
android·linux·服务器
圥忈&&丅佽&&扗虖3 小时前
linux 安装docker和docker-compose
linux·运维·docker
czxyvX11 小时前
007-Linux进程概念及周边知识
linux
Eternity∞12 小时前
Linux系统下,C语言基础
linux·c语言·开发语言
feng68_12 小时前
HAProxy算法实践
linux·运维·haproxy
吹牛不交税14 小时前
在vmware中右键SSH连接虚拟机报错Could not resolve hostname
linux·服务器·ssh
鱼香rose__15 小时前
DOMjudge搭建记录
linux