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

发布时间:2026/7/25 3:35:41
设备树 DTS 工控硬件配置:串口、CAN、GPIO、看门狗硬件资源配置 设备树 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 CompilerDTS→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 { cpu0 { compatible arm,cortex-a7; device_type cpu; reg 0; /* CPU编号 */ }; }; memory80000000 { device_type memory; reg 0x80000000 0x20000000; /* 起始地址大小 512MB */ }; };关键语法要点compatible是驱动匹配的核心——内核根据这个字符串找对应驱动reg属性格式取决于父节点的#address-cells和#size-cells字符串属性用双引号数值用布尔属性写上名字就行存在即true2.2 兼容字符串compatiblecompatible是DTS中最重要的属性格式为vendor,devicecompatible 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.dts3.2 DTB加载方式U-Boot加载DTB有两种方式# 方式1DTB单独加载tftp 0x82000000 myboard.dtb tftp 0x80008000 zImage bootz 0x80008000 - 0x82000000# 方式2DTB附加在内核镜像后现代方式# 内核编译时CONFIG_ARM_APPENDED_DTBycatzImage myboard.dtbzImage_with_dtb内核启动后设备树信息可以在/proc/device-tree/查看ls/proc/device-tree/# 可以看到所有节点目录cat/proc/device-tree/model# 输出板子名称四、串口配置实战串口是工控最基础的通信接口DTS配置决定了内核能识别出哪些串口、用什么参数。4.1 UART节点配置/* AM335x平台串口配置示例 */ uart0: serial44e09000 { 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: serial48022000 { 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: can481cc000 { 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: gpio44e07000 { 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: watchdog44e35000 { compatible ti,am3352-wdt; reg 0x44e35000 0x1000; interrupts 93; status okay; /* 看门狗超时时间秒 */ timeout-sec 30; /* 喂狗方式 * - magic-close: 关闭设备文件时必须写入特定字符V才停止看门狗 * 防止意外关闭导致看门狗失效 */ };用户空间喂狗程序#includestdio.h#includefcntl.h#includeunistd.h#includelinux/watchdog.hintmain(void){intfdopen(/dev/watchdog,O_WRONLY);if(fd0){perror(open watchdog);return-1;}/* 设置超时30秒 */inttimeout30;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机制设备树OverlayDTO允许在基础DTS上叠加修改不改原始文件。适合工控场景基础板配置固定扩展板动态叠加。/* 基础板DTS: myboard.dts */ / { uart3: serial48024000 { status disabled; /* 默认禁用扩展板启用 */ }; }; /* Overlay文件: myboard-can-extension.dtso */ /dts-v1/; /plugin/; / { fragment0 { target uart3; __overlay__ { status okay; /* 启用串口3 */ current-speed 115200; }; }; };编译和应用Overlaydtc-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后串口不出现原因排序status没改okay——最常见的低级错误节点默认disabledpinctrl没配置——引脚还复用给其他功能串口拿不到物理pincompatible字符串不匹配——内核找不到对应驱动reg地址写错——寄存器地址和硬件手册不一致排查步骤# 查看内核是否识别了设备节点ls/proc/device-tree/serial44e09000/# 查看内核日志dmesg|grepuart# 查看pinctrl状态cat/sys/kernel/debug/pinctrl/pinctrl-maps# 查看驱动匹配cat/sys/bus/platform/devices/44e09000.serial/driver/modalias9.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 */ }; memory80000000 { 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的轻松操作。