尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

设备树 DTS 工控硬件配置:串口、CAN、GPIO、看门狗硬件资源配置

设备树 DTS 工控硬件配置:串口、CAN、GPIO、看门狗硬件资源配置
📅 发布时间:2026/7/25 3:54:51

设备树 DTS 工控硬件配置:串口、CAN、GPIO、看门狗硬件资源配置

设备树是Linux内核的"硬件简历"——告诉内核板子上有什么资源、怎么接线,比源码里硬编码优雅一万倍。

一、设备树概念与作用

在Linux 3.x之前,硬件信息硬编码在内核源码的arch/arm/mach-xxx目录里,每换一块板子就要改内核代码、重新编译——痛苦指数极高。

设备树(Device Tree)的出现改变了这一切:硬件配置信息从内核代码中剥离出来,变成独立的.dts文件描述。内核启动时加载设备树,按描述初始化硬件——换板子只换设备树文件,不改内核。

类比理解:设备树就像一份"硬件清单"——内核是装修队,设备树告诉装修队"这个房间有3个插座、2个水龙头、1个空调接口",装修队照单施工。

核心术语:

术语说明
DTSDevice Tree Source,人类可读的文本源文件
DTSIDevice Tree Source Include,可被其他DTS包含的公共片段
DTBDevice Tree Blob,编译后的二进制文件,内核实际加载的格式
DTCDevice Tree Compiler,DTS→DTB的编译工具
compatible兼容字符串,匹配内核驱动的关键标识

二、DTS文件语法基础

2.1 节点与属性

DTS的基本结构是节点树,每个节点用{}包裹,属性用key = value定义:

/dts-v1/; /* DTS版本声明 */ / { /* 根节点,代表整块板子 */ model = "MyBoard v2.0"; /* 板子名称 */ compatible = "myvendor,myboard", "arm,cortex-a7"; /* 兼容字符串 */ #address-cells = <1>; /* 地址用1个32位单元格表示 */ #size-cells = <1>; /* 大小用1个32位单元格表示 */ cpus { cpu@0 { compatible = "arm,cortex-a7"; device_type = "cpu"; reg = <0>; /* CPU编号 */ }; }; memory@80000000 { device_type = "memory"; reg = <0x80000000 0x20000000>; /* 起始地址+大小 = 512MB */ }; };

关键语法要点:

  • compatible是驱动匹配的核心——内核根据这个字符串找对应驱动
  • reg属性格式取决于父节点的#address-cells和#size-cells
  • 字符串属性用双引号,数值用<>,布尔属性写上名字就行(存在即true)

2.2 兼容字符串(compatible)

compatible是DTS中最重要的属性,格式为"vendor,device":

compatible = "ti,am3352", "ti,am33xx"; /* 优先匹配ti,am3352驱动,找不到再匹配ti,am33xx */

内核驱动中注册的ID表必须与compatible一致,否则驱动不会绑定到这个节点。

三、DTS编译流程

DTS源文件 (.dts/.dtsi) ↓ dtc编译器 (Device Tree Compiler) ↓ DTB二进制文件 (.dtb) ↓ bootloader传递给内核 (U-Boot: bootm / fdt) ↓ 内核解析DTB,创建设备节点

3.1 dtc编译命令

# 安装dtcapt-getinstalldevice-tree-compiler# Debian/Ubuntu# 编译DTS为DTBdtc-Idts-Odtb-omyboard.dtb myboard.dts# 反编译DTB为DTS(调试时有用)dtc-Idtb-Odts-omyboard.dts myboard.dtb# 带包含路径编译dtc-Idts-Odtb-iinclude/-omyboard.dtb myboard.dts

3.2 DTB加载方式

U-Boot加载DTB有两种方式:

# 方式1:DTB单独加载tftp 0x82000000 myboard.dtb tftp 0x80008000 zImage bootz 0x80008000 - 0x82000000# 方式2:DTB附加在内核镜像后(现代方式)# 内核编译时CONFIG_ARM_APPENDED_DTB=ycatzImage myboard.dtb>zImage_with_dtb

内核启动后,设备树信息可以在/proc/device-tree/查看:

ls/proc/device-tree/# 可以看到所有节点目录cat/proc/device-tree/model# 输出板子名称

四、串口配置实战

串口是工控最基础的通信接口,DTS配置决定了内核能识别出哪些串口、用什么参数。

4.1 UART节点配置

/* AM335x平台串口配置示例 */ uart0: serial@44e09000 { compatible = "ti,am3352-uart", "ti,omap3-uart"; reg = <0x44e09000 0x2000>; /* 寄存器地址范围 */ interrupts = <72>; /* 中断号 */ clock-frequency = <48000000>; /* 输入时钟频率 */ status = "okay"; /* okay=启用, disabled=禁用 */ /* 自定义属性:默认波特率 */ current-speed = <115200>; /* DMA配置(可选,大数据量时启用) */ dmas = <&edma 28 0>, <&edma 29 0>; dma-names = "rx", "tx"; }; /* 工控扩展串口(连接PLC) */ uart1: serial@48022000 { compatible = "ti,am3352-uart"; reg = <0x48022000 0x2000>; interrupts = <73>; status = "okay"; current-speed = <9600>; /* PLC通信波特率9600 */ };

关键属性解析:

  • status:只有写"okay"才生效,"disabled"的节点内核不会注册
  • current-speed:部分驱动支持从DTS读取默认波特率
  • DMA配置:高速串口(如48MHz时钟)配合DMA可减少CPU中断开销

4.2 引脚复用(pinctrl)

串口引脚可能和其他功能复用同一个物理pin,必须在DTS中明确声明:

&am33xx_pinmux { uart0_pins: pinmux_uart0_pins { pinctrl-single,bits = < 0x170 0x30 /* RXD */ 0x174 0x00 /* TXD */ >; }; }; &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pins>; };

五、CAN配置实战

CAN总线是工控的"标配"通信方式,DTS配置CAN控制器和波特率。

/* CAN节点配置 */ dcan0: can@481cc000 { compatible = "ti,am3352-dcan"; reg = <0x481cc000 0x2000>; interrupts = <52>; clocks = <&dcan0_fck>; status = "okay"; /* CAN波特率配置 */ /* CAN标准波特率通过clock-freq和bit-timing计算 */ /* 500kbps典型配置 */ }; /* CAN引脚复用 */ &am33xx_pinmux { dcan0_pins: pinmux_dcan0_pins { pinctrl-single,bits = < 0x178 0x20 /* CAN_RX */ 0x17c 0x20 /* CAN_TX */ >; }; }; &dcan0 { pinctrl-names = "default"; pinctrl-0 = <&dcan0_pins>; };

CAN波特率通过ip命令配置(内核启动后):

iplinksetcan0typecan bitrate500000iplinksetcan0 up

六、GPIO配置实战

GPIO是工控的"万能接口"——控制继电器、读取开关状态、驱动LED,全靠它。

6.1 GPIO控制器节点

gpio0: gpio@44e07000 { compatible = "ti,am3352-gpio"; reg = <0x44e07000 0x1000>; interrupts = <96>; gpio-controller; /* 标记这是一个GPIO控制器 */ #gpio-cells = <2>; /* 引用时需要2个参数: bank编号+偏移 */ ngpio = <32>; /* GPIO总数 */ status = "okay"; };

6.2 GPIO作为设备引脚使用

/* LED设备,使用GPIO pin */ leds { compatible = "gpio-leds"; led0 { label = "status-led"; gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>; /* gpio0 bank, pin21, 高电平亮 */ default-state = "off"; }; led1 { label = "alarm-led"; gpios = <&gpio1 15 GPIO_ACTIVE_LOW>; /* 低电平亮 */ default-state = "off"; }; }; /* 继电器控制 */ relay-controller { compatible = "myvendor,relay"; gpios = <&gpio2 0 GPIO_ACTIVE_HIGH>, /* 继电器1 */ <&gpio2 1 GPIO_ACTIVE_HIGH>; /* 继电器2 */ relay-count = <2>; };

<&gpio0 21 GPIO_ACTIVE_HIGH>含义:引用gpio0控制器,第21号引脚,高电平有效。

6.3 pinctrl引脚复用

&am33xx_pinmux { gpio_pins: pinmux_gpio_pins { pinctrl-single,bits = < /* 配置为GPIO模式而非串口/SPI等 */ 0x1a0 0x7f /* GPIO2_0 */ 0x1a4 0x7f /* GPIO2_1 */ >; }; };

七、看门狗配置实战

看门狗(Watchdog)是工控系统的"保险丝"——程序卡死时自动重启,防止设备永久挂死。

/* 看门狗节点 */ wdt: watchdog@44e35000 { compatible = "ti,am3352-wdt"; reg = <0x44e35000 0x1000>; interrupts = <93>; status = "okay"; /* 看门狗超时时间(秒) */ timeout-sec = <30>; /* 喂狗方式: * - "magic-close": 关闭设备文件时必须写入特定字符'V'才停止看门狗 * 防止意外关闭导致看门狗失效 */ };

用户空间喂狗程序:

#include<stdio.h>#include<fcntl.h>#include<unistd.h>#include<linux/watchdog.h>intmain(void){intfd=open("/dev/watchdog",O_WRONLY);if(fd<0){perror("open watchdog");return-1;}/* 设置超时30秒 */inttimeout=30;ioctl(fd,WDIOC_SETTIMEOUT,&timeout);while(1){/* 喂狗:写入任意一个字节 */write(fd,"\0",1);printf("喂狗成功\n");sleep(10);/* 每10秒喂一次,小于30秒超时 */}/* 正常退出时写入'V'停止看门狗 */write(fd,"V",1);close(fd);return0;}

注意:如果程序崩溃退出没写’V’,看门狗会继续计时,30秒后触发硬件重启——这正是看门狗的"保险"作用。

八、自定义DTS覆盖板级配置(Overlay机制)

设备树Overlay(DTO)允许在基础DTS上叠加修改,不改原始文件。适合工控场景:基础板配置固定,扩展板动态叠加。

/* 基础板DTS: myboard.dts */ / { uart3: serial@48024000 { status = "disabled"; /* 默认禁用,扩展板启用 */ }; }; /* Overlay文件: myboard-can-extension.dtso */ /dts-v1/; /plugin/; / { fragment@0 { target = <&uart3>; __overlay__ { status = "okay"; /* 启用串口3 */ current-speed = <115200>; }; }; };

编译和应用Overlay:

dtc-Idts-Odtb -@-ooverlay.dtbo overlay.dtso# 内核运行时动态加载mkdir/sys/kernel/config/device-tree/overlays/my-overlaycatoverlay.dtbo>/sys/kernel/config/device-tree/overlays/my-overlay/dtbo

九、常见问题排查

9.1 修改DTS后串口不出现

原因排序:

  1. status没改okay——最常见的低级错误,节点默认disabled
  2. pinctrl没配置——引脚还复用给其他功能,串口拿不到物理pin
  3. compatible字符串不匹配——内核找不到对应驱动
  4. reg地址写错——寄存器地址和硬件手册不一致

排查步骤:

# 查看内核是否识别了设备节点ls/proc/device-tree/serial@44e09000/# 查看内核日志dmesg|grepuart# 查看pinctrl状态cat/sys/kernel/debug/pinctrl/pinctrl-maps# 查看驱动匹配cat/sys/bus/platform/devices/44e09000.serial/driver/modalias

9.2 引脚冲突

两个设备要求同一个pin做不同功能,内核只会给先申请的那个:

# 查看引脚当前配置cat/sys/kernel/debug/pinctrl/pinctrl-maps|greppin48# 输出会显示pin48被哪个设备占了# 解决:在DTS中确保每个pin只被一个设备引用

十、完整DTS配置示例

以下是一份工控板的完整DTS配置(基于AM335x平台),涵盖串口、CAN、GPIO、看门狗:

/dts-v1/; #include "am335x.dtsi" /* 芯片级基础定义 */ / { model = "ICBoard-AM335x-v2"; compatible = "myvendor,icboard", "ti,am3352"; chosen { stdout-path = &uart0; /* 系统console用uart0 */ }; memory@80000000 { device_type = "memory"; reg = <0x80000000 0x20000000>; }; /* LED指示灯 */ leds { compatible = "gpio-leds"; pinctrl-names = "default"; pinctrl-0 = <&led_pins>; led-status { label = "status"; gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; }; led-alarm { label = "alarm"; gpios = <&gpio1 15 GPIO_ACTIVE_LOW>; default-state = "off"; }; }; /* 继电器 */ relays { compatible = "gpio-relays"; pinctrl-names = "default"; pinctrl-0 = <&relay_pins>; gpios = <&gpio2 0 GPIO_ACTIVE_HIGH>, <&gpio2 1 GPIO_ACTIVE_HIGH>; }; }; /* 引脚复用配置 */ &am33xx_pinmux { uart0_pins: pinmux_uart0_pins { pinctrl-single,bits = <0x170 0x30 0x174 0x00>; }; uart1_pins: pinmux_uart1_pins { pinctrl-single,bits = <0x180 0x20 0x184 0x00>; }; dcan0_pins: pinmux_dcan0_pins { pinctrl-single,bits = <0x178 0x20 0x17c 0x20>; }; led_pins: pinmux_led_pins { pinctrl-single,bits = <0x1a0 0x7f>; }; relay_pins: pinmux_relay_pins { pinctrl-single,bits = <0x1a4 0x7f 0x1a8 0x7f>; }; }; /* 串口配置 */ &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pins>; status = "okay"; current-speed = <115200>; }; &uart1 { pinctrl-names = "default"; pinctrl-0 = <&uart1_pins>; status = "okay"; current-speed = <9600>; /* PLC通信 */ }; /* CAN配置 */ &dcan0 { pinctrl-names = "default"; pinctrl-0 = <&dcan0_pins>; status = "okay"; }; /* 看门狗 */ &wdt { status = "okay"; timeout-sec = <30>; };

设备树把硬件配置从内核代码中解放出来,DTS文件清晰可读、修改方便、不用重编译内核。串口、CAN、GPIO、看门狗——工控四大硬件资源的配置,全在这一份文本文件中搞定。改配置、换板子,从"改内核源码+重新编译"的噩梦,变成了"改几行文本+编译dtb"的轻松操作。

相关新闻

  • AI工具如何提升本科开题报告写作效率与质量
  • 容器里的 1 号进程:为什么 kill 不掉?僵尸进程又从哪来?
  • 从概念车到竞赛利器:如何理性看待自行车新技术与性能指标

最新新闻

  • 黄石本地防水补漏精选TOP5推荐:正规漏水检测维修公司上门师傅推荐:厕所/棚顶/屋面/飘窗/阳台/地下室/厨房渗漏水精准测漏维修(2026最新) - 即刻修防水
  • C++函数模板:从代码复用原理到泛型编程实战
  • AI写推荐信的致命误区:87%用户踩中的“人格稀释”雷区,及5步反向提示工程修复方案
  • Dev-C++入门指南:轻量级C++开发环境配置与使用详解
  • 免费AI编程助手:Codex客户端集成DeepSeek大模型全攻略
  • 2026年7月工程合同律师/河南劳动合同律师事务所口碑排行_宁乔姬 - 行业平台推荐

日新闻

  • 从国家条件到买方清单,深入理解 ABAP CDS 单值过滤器派生
  • 2026 年当下,齐齐哈尔专业的不锈钢闸门批发厂家哪个好,揭秘!这个工业“铁门”如何实现成本翻倍的效率提升? - 行业甄选官
  • 2026阳极氧化加工厂推荐:从设备规模看硬质氧化技术的成熟应用推荐百正机械 - 栗子测评

周新闻

  • SaaS软件行业GEO实践:AI搜索时代的品牌可见性与获客新路径
  • 什么是PCTFE?医药高端包装的“防潮王牌“材料
  • 【JVM调优实战】16-可视化利器-JConsole-VisualVM-JMC

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号