当前位置:首页 > 嵌入式 > 嵌入式分享
[导读]在嵌入式Linux开发中,设备树(Device Tree)已成为描述硬件的标准。它让内核与硬件解耦,实现“一份内核,适配万千板卡”。本文将跳过繁杂的理论,直击设备树节点编写与内核驱动匹配的核心流程。



在嵌入式Linux开发中,设备树(Device Tree)已成为描述硬件的标准。它让内核与硬件解耦,实现“一份内核,适配万千板卡”。本文将跳过繁杂的理论,直击设备树节点编写与内核驱动匹配的核心流程。


一、设备树基础:从“硬件图纸”到DTS


设备树的核心结构是节点(Node)和属性(Property)。一个节点代表一个硬件设备。


1. 标准节点结构


// 在 arch/arm/boot/dts/my_board.dts

/ {

   model = "My Custom Board";

   compatible = "myvendor,my-board-v1";


   chosen {

       bootargs = "console=ttyS0,115200 root=/dev/mmcblk0p2";

   };


   memory@80000000 {

       device_type = "memory";

       reg = <0x80000000 0x20000000>; // 起始地址 + 长度 (512MB)

   };

};


关键点:根节点/下的model和compatible用于内核识别板卡;reg属性是地址描述的核心。


二、添加自定义外设节点(I2C设备为例)


假设板上有一个挂载在I2C1控制器下的EEPROM。


1. 查找控制器节点


首先,在SoC的DTSI文件(如soc.dtsi)中找到I2C控制器节点,获取其#address-cells和#size-cells。


2. 编写设备节点


// 在 my_board.dts 中

&i2c1 { // 引用已有的i2c1控制器节点

   status = "okay"; // 确保控制器使能

   clock-frequency = <100000>; // 100kHz


   eeprom@50 {

       compatible = "atmel,24c08"; // 关键:用于匹配驱动

       reg = <0x50>;             // I2C从设备地址

       pagesize = <16>;          // 设备特有属性

       read-only;                // 布尔属性(无值)

   };

};


注意:&i2c1表示追加或修改原有节点;reg的格式和长度必须与父节点的#address-cells匹配。


三、驱动与设备树的“联姻”:Of Match Table


设备树节点如何找到对应的驱动?答案是compatible字符串。


1. 内核驱动中的匹配表


在驱动代码中,定义一个of_device_id结构体数组。

// drivers/misc/my_eeprom.c

static const struct of_device_id eeprom_of_match[] = {

   { .compatible = "atmel,24c08" }, // 必须与DTS中的字符串完全一致

   { .compatible = "atmel,24c256" },

   { /* Sentinel */ }

};

MODULE_DEVICE_TABLE(of, eeprom_of_match);


static struct platform_driver eeprom_driver = {

   .probe = eeprom_probe,

   .remove = eeprom_remove,

   .driver = {

       .name = "my_eeprom",

       .of_match_table = eeprom_of_match, // 绑定匹配表

   },

};



2. 驱动获取设备树属性


当compatible匹配成功后,内核会调用驱动的probe函数,此时可以通过of_系列API读取DTS属性。

static int eeprom_probe(struct platform_device *pdev)

{

   struct device_node *np = pdev->dev.of_node;

   u32 reg_addr;

   int ret;


   // 获取reg属性

   ret = of_property_read_u32(np, "reg", &reg_addr);

   if (ret) {

       dev_err(&pdev->dev, "Failed to get reg property\n");

       return ret;

   }


   // 判断布尔属性是否存在

   if (of_property_read_bool(np, "read-only")) {

       dev_info(&pdev->dev, "Device is read-only\n");

   }


   // 获取pagesize

   of_property_read_u32(np, "pagesize", &priv->page_size);


   // ... 初始化硬件 ...

   return 0;

}



四、Pinctrl与GPIO:复杂硬件的绑定


对于GPIO或引脚复用,设备树需要与pinctrl子系统配合。

// 定义引脚配置

&iomuxc {

   pinctrl_eeprom: eepromgrp {

       fsl,pins = <

           MX6QDL_PAD_EIM_D17__GPIO3_IO17 0x80000000

       >;

   };

};


// 在设备节点中引用

&i2c1 {

   eeprom@50 {

       compatible = "atmel,24c08";

       reg = <0x50>;

       pinctrl-names = "default";

       pinctrl-0 = <&pinctrl_eeprom>; // 绑定引脚配置

       wp-gpios = <&gpio3 17 GPIO_ACTIVE_LOW>; // 写保护GPIO

   };

};


驱动中通过gpiod_get()获取wp-gpios,无需关心具体引脚号。


五、调试与验证技巧


1.  编译与反编译

   # 编译DTB

   make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- my_board.dtb

   # 反编译DTB查看最终节点(非常有用!)

   dtc -I dtb -O dts my_board.dtb > decompiled.dts

   

   很多时候DTS写对了,但被DTSI覆盖了,反编译能看到最终生效的配置。


2.  内核启动后验证

   # 查看设备树节点

   ls /proc/device-tree/

   # 查看特定属性

   hexdump -C /proc/device-tree/soc/i2c@21a0000/eeprom@50/compatible

   # 查看GPIO分配

   cat /sys/kernel/debug/gpio

   


六、结语


编写设备树的关键在于“描述准确”与“匹配无误”。遵循三步法:定义节点与属性 → 驱动中实现of_match_table → 使用of_property_read_* API读取数据。掌握设备树,你就掌握了嵌入式Linux硬件适配的钥匙。


本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
换一批
延伸阅读

在物联网设备日益普及的今天,固件空中升级(OTA)已成为设备维护和功能更新的标准方式。A/B分区架构结合差分升级技术,能够在保证系统高可用性的同时,显著降低传输数据量,特别适合带宽受限的嵌入式环境。本文将深入探讨A/B分...

关键字: 固件升级 OTA 嵌入式Linux

在嵌入式Linux开发中,设备树(Device Tree)已成为硬件描述与内核解耦的核心机制。传统静态设备树在编译时固化硬件信息,难以适应多变的硬件配置需求。而动态设备树配置技术通过设备树叠加(Overlay)机制,允许...

关键字: 嵌入式Linux 设备树

在嵌入式Linux开发中,开发者常面临目标设备资源受限(如ARM Cortex-A系列处理器、低内存配置)的挑战,无法直接在设备上完成代码编译与调试。交叉编译与远程调试技术通过“宿主机-目标机”分离架构,将编译与调试任务...

关键字: 嵌入式Linux 交叉编译 远程调试

在嵌入式Linux开发中,多线程技术是提升系统并发处理能力的核心手段。然而,从“能跑”到“稳定”的跨越,需要开发者深入理解并发本质、同步机制与工程实践原则。

关键字: 嵌入式Linux 多线程

在嵌入式Linux开发中,快速获取系统状态信息是调试和监控的关键能力。本文整理了7个高频使用的C语言代码片段,涵盖内存、CPU温度、文件操作等核心场景,帮助开发者高效实现系统状态采集。

关键字: 嵌入式Linux C语言

在物联网设备与工业控制系统广泛应用的嵌入式Linux场景中,系统安全已成为制约产业发展的核心痛点。Red Hat安全报告显示,正确配置的SELinux可拦截超过90%的权限提升攻击,而结合审计子系统(auditd)的实时...

关键字: 嵌入式Linux SELinux

智能家居设备对实时性要求日益提升,嵌入式Linux系统的启动时间优化成为提升用户体验的关键。通过内核裁剪、文件系统精简、并行化启动及硬件加速等策略,可将典型智能家居设备的启动时间从数十秒压缩至1秒以内。本文从技术实现角度...

关键字: 嵌入式Linux 智能家居

在工业物联网设备、边缘计算节点等嵌入式Linux场景中,系统可用性直接关系到业务连续性。传统内核更新需要数小时的停机窗口,而Kpatch技术通过动态函数替换机制,实现了零停机时间的安全修复。以某智能电网终端设备为例,采用...

关键字: 嵌入式Linux 热补丁 Kpatch

在工业物联网网关、智能车载设备等嵌入式场景中,系统启动时间直接影响用户体验与设备可用性。某智能电表项目测试显示,未经优化的Linux系统启动耗时达12.7秒,而通过内核裁剪与initramfs定制可缩短至1.8秒。本文聚...

关键字: 工业物联网 嵌入式Linux initramfs

在嵌入式Linux开发中,设备树(Device Tree)已成为硬件抽象的核心机制,其通过动态描述硬件资源,使内核能够灵活适配不同硬件平台。本文聚焦GPIO与中断资源的设备树映射技术,结合实际案例解析其配置方法与优化策略...

关键字: 嵌入式Linux 设备树 GPIO
关闭