Linux驱动开发必备:手把手教你编译自定义设备树(dts文件)

张开发
2026/4/11 13:21:13 15 分钟阅读

分享文章

Linux驱动开发必备:手把手教你编译自定义设备树(dts文件)
Linux驱动开发实战从零构建与优化自定义设备树为什么设备树成为现代Linux驱动的核心在嵌入式Linux开发领域设备树已经彻底改变了硬件描述的方式。想象一下你拿到一块全新的开发板传统方式需要为每个外设编写大量板级支持包代码而现在只需要一个结构化的文本文件就能完整描述硬件拓扑——这就是设备树带来的革命。设备树源文件.dts本质上是一种硬件描述语言它采用树状结构定义处理器、内存范围、总线设备和各类外设寄存器。与过去硬编码在内核中的硬件描述相比设备树实现了硬件配置与内核代码的解耦。当我们需要支持新硬件时不再需要重新编译内核只需提供对应的设备树二进制文件.dtb。这种机制特别适合当今碎片化的嵌入式市场。同一款SoC可能被用在数十种不同的板卡上每种板卡的外设连接方式各不相同。通过设备树我们可以为每个变体创建独立的描述文件而共享同一套内核镜像。根据2023年Linux基金会报告超过90%的ARM架构新项目都采用了纯设备树方式启动。设备树开发环境搭建工具链准备开始设备树开发前需要确保你的系统具备以下工具sudo apt-get install gcc-arm-linux-gnueabihf dtc device-tree-compiler验证工具链是否安装正确dtc --version # 应输出类似Version: DTC 1.6.1内核源码配置大多数情况下我们需要获取与目标板卡匹配的内核源码。以i.MX6ULL为例git clone https://github.com/Freescale/linux-fslc.git cd linux-fslc git checkout 5.15-2.1.x-imx关键目录结构说明目录路径内容说明arch/arm/boot/dts/存放所有设备树源文件scripts/dtc/设备树编译器源码include/dt-bindings/标准设备树绑定定义提示建议在开发机上创建独立的开发环境可以使用Docker容器或虚拟机保持环境纯净。设备树语法深度解析基础节点结构一个典型的设备树文件由若干节点组成每个节点描述一个硬件组件。以下是GPIO控制器的定义示例gpio1: gpio0209c000 { compatible fsl,imx6ul-gpio, fsl,imx35-gpio; reg 0x0209c000 0x4000; interrupts GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH, GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH; gpio-controller; #gpio-cells 2; interrupt-controller; #interrupt-cells 2; };关键属性解析compatible驱动匹配字符串格式通常为厂商,芯片-功能reg寄存器地址范围格式为起始地址 长度interrupts中断号定义包含控制器、编号和触发方式高级特性应用现代设备树支持许多强大特性合理使用可以大幅提升代码质量地址映射技术memory80000000 { device_type memory; reg 0x80000000 0x20000000; }; reserved-memory { #address-cells 1; #size-cells 1; ranges; linux,cma { compatible shared-dma-pool; reusable; size 0x10000000; linux,cma-default; }; };条件编译支持#if defined(CONFIG_TOUCHSCREEN_GT911) i2c1 { touchscreen5d { compatible goodix,gt911; reg 0x5d; interrupt-parent gpio1; interrupts 9 IRQ_TYPE_EDGE_FALLING; }; }; #endif实战从零创建自定义设备树板级基础框架搭建以i.MX6ULL为例新建自定义板卡的设备树文件cp arch/arm/boot/dts/imx6ull-14x14-evk.dts arch/arm/boot/dts/imx6ull-myboard.dts基础框架必须包含头部版本声明SoC级包含文件板级特殊定义外设节点覆盖典型结构示例/dts-v1/; #include imx6ull.dtsi #include imx6ull-pinfunc.h / { model My Custom i.MX6ULL Board; compatible my,imx6ull-myboard, fsl,imx6ull; memory80000000 { device_type memory; reg 0x80000000 0x20000000; }; /* 板级特定定义 */ };外设集成技巧LED控制实现leds { compatible gpio-leds; status okay; user-led { label heartbeat; gpios gpio1 5 GPIO_ACTIVE_LOW; linux,default-trigger heartbeat; }; };以太网PHY配置fec1 { pinctrl-names default; pinctrl-0 pinctrl_enet1; phy-mode rmii; phy-handle ethphy0; status okay; mdio { #address-cells 1; #size-cells 0; ethphy0: ethernet-phy0 { compatible ethernet-phy-id0022.1560; reg 0; reset-gpios gpio1 9 GPIO_ACTIVE_LOW; reset-assert-us 10000; reset-deassert-us 1000; }; }; };编译与调试全流程多模式编译方法完整内核编译make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- imx_v7_defconfig make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- -j8仅编译设备树make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- dtbs编译单个设备树文件make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- imx6ull-myboard.dtb调试技巧大全反编译DTB文件dtc -I dtb -O dts -o debug.dts imx6ull-myboard.dtb运行时设备树查看# 在目标板上执行 ls /proc/device-tree/ cat /proc/device-tree/model内核调试信息启用在内核配置中开启CONFIG_DEBUG_DRIVERy CONFIG_DEBUG_DEVICE_TREEy常见编译错误处理错误类型解决方案Syntax error使用dtc --strict检查语法Undefined reference确认包含的dtsi文件路径正确Address/size mismatch检查reg属性与芯片手册一致性性能优化与高级技巧设备树预处理技术利用C预处理器实现条件编译DTS_FLAGS -DUSE_TOUCHSCREEN1在dts文件中#if USE_TOUCHSCREEN i2c1 { touchscreen38 { /* 配置详情 */ }; }; #endif内存布局优化reserved-memory { #address-cells 1; #size-cells 1; ranges; gpu_reserved: gpu88000000 { no-map; reg 0x88000000 0x1000000; }; v4l2_reserved: v4l289000000 { no-map; reg 0x89000000 0x2000000; }; };启动时间优化策略按需加载驱动合理使用status disabled减少探测延迟正确设置时钟频率和初始化时序并行初始化优化节点依赖关系usdhc1 { status okay; pinctrl-names default, state_100mhz, state_200mhz; pinctrl-0 pinctrl_usdhc1; pinctrl-1 pinctrl_usdhc1_100mhz; pinctrl-2 pinctrl_usdhc1_200mhz; bus-width 4; no-1-8-v; keep-power-in-suspend; non-removable; wakeup-source; vmmc-supply ®_sd1_vmmc; max-frequency 100000000; assigned-clocks clks IMX6UL_CLK_USDHC1; assigned-clock-rates 100000000; };常见问题与解决方案硬件不匹配问题排查典型症状内核启动时外设未初始化驱动加载但功能异常系统运行不稳定排查步骤确认设备树节点compatible字符串与驱动匹配检查寄存器地址和中断号是否正确验证时钟配置和电源管理设置使用devmem2工具直接读取硬件寄存器版本兼容性处理不同内核版本对设备树的处理可能有差异内核版本设备树特性变化4.14新的时钟绑定规范5.4改进的电源管理节点5.10增强的DMA池管理调试工具推荐dtc设备树编译器支持语法检查和反编译fdtdump直接查看DTB文件内容devicetree-rebundle设备树重构工具dt-gui图形化设备树编辑器# 使用fdtdump分析DTB结构 fdtdump imx6ull-myboard.dtb | less进阶开发方向动态设备树技术现代Linux内核支持运行时修改设备树// 内核模块中动态添加节点 struct device_node *np of_find_node_by_path(/); struct property *newprop kzalloc(sizeof(*newprop), GFP_KERNEL); newprop-name dynamic-prop; newprop-value test-value; newprop-length strlen(newprop-value); of_add_property(np, newprop);设备树单元测试使用dtc的单元测试框架dtc - -O dtb -o test.dtb test.dts dtc -O dts test.dtb test_out.dts diff -u test.dts test_out.dts自动化生成工具对于复杂硬件可以考虑使用工具生成基础设备树import yaml import dtgen with open(hardware_spec.yaml) as f: spec yaml.safe_load(f) dt dtgen.DeviceTree() dt.generate_from_spec(spec) dt.write(auto_generated.dts)

更多文章