设备树(Device Tree)是一种描述硬件资源的数据结构,它通过一种树状结构来描述系统中的硬件设备信息。在Zynq系统中,设备树主要用来描述:
设备树(Device Tree)用于描述硬件配置信息,将硬件描述与驱动代码分离。通过.dts
(设备树源文件)编译为.dtb
(二进制设备树),供Linux内核在启动时解析硬件信息。
system-top.dts
)。.h
文件,供DTS文件包含(如pl.dtsi
、pcw.dtsi
)。.dts
为.dtb
。compatible
:驱动匹配的关键属性,格式为" manufacturer,device-type"
。reg
:描述硬件寄存器地址和大小。status
:设备状态(okay
或disabled
)。#address-cells
和#size-cells
:定义地址和大小的单元数。.xsa
文件(File → Export → Export hardware)。File → New → Board Support Package
。Apply and Close
,生成设备树文件(system-top.dts
、pl.dtsi
、pcw.dtsi
等)。device-tree-xlnx
),解压到SDK安装目录(如/Xilinx/SDK/data embeddedsw
)。Xilinx → repositories
添加资源包路径。device_tree
选项,配置启动参数(如console=ttyPS0,115200 root=/dev/mmcblk0p2
)。project-spec/meta-user/recipes-bsp/devicetree/files
目录。一个典型的Zynq设备树文件结构如下:
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
compatible = "xlnx,zynq-7000";
model = "Xilinx Zynq";
cpus {
/* CPU信息 */
};
memory {
/* 内存信息 */
};
amba {
/* 外设信息 */
};
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "arm,cortex-a9";
device_type = "cpu";
reg = <0>;
clocks = <&clkc 3>;
clock-latency = <1000>;
cpu0-supply = <®ulator_vccpint>;
operating-points = <
/* kHz uV */
666667 1000000
333334 1000000
>;
};
};
memory {
device_type = "memory";
reg = <0x0 0x40000000>;
};
amba {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&intc>;
ranges;
/* 外设定义在这里 */
};
system-top.dts
:主设备树文件,包含所有硬件配置。pl.dtsi
:描述PL(可编程逻辑)端的外设。pcw.dtsi
:描述PS(处理系统)端的外设。system-user.dtsi
:用户自定义修改的优先级最高。status
属性从disabled
改为okay
(如SD卡控制器)。system-user.dtsi
中添加节点,例如SPI控制器:&spiflash {
compatible = "xlnx,spiflash";
reg = ;
status = "okay";
#address-cells = ;
#size-cells = ;
};
clocks
和interrupts
属性,确保与硬件设计一致。dtc
工具编译:dtc -I dts -O dtb -o output.dtb input.dts
petalinux-config
配置设备树路径,重新编译内核。在Vivado中完成设计后:
假设我们有一个自定义的AXI GPIO IP核:
amba {
my_gpio: gpio@41200000 {
compatible = "xlnx,xps-gpio-1.00.a";
reg = <0x41200000 0x10000>;
interrupts = <0 29 4>;
interrupt-parent = <&intc>;
#gpio-cells = <2>;
gpio-controller;
xlnx,all-inputs = <0>;
xlnx,all-inputs-2 = <0>;
xlnx,all-outputs = <1>;
xlnx,all-outputs-2 = <0>;
xlnx,dout-default = <0x0>;
xlnx,dout-default-2 = <0x0>;
xlnx,gpio-width = <8>;
xlnx,gpio2-width = <32>;
xlnx,interrupt-present = <1>;
xlnx,is-dual = <0>;
xlnx,tri-default = <0xFFFFFFFF>;
xlnx,tri-default-2 = <0xFFFFFFFF>;
};
};
Zynq中的中断定义:
intc: interrupt-controller@f8f01000 {
compatible = "arm,gic-400", "arm,cortex-a9-gic";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0xF8F01000 0x1000>,
<0xF8F00100 0x100>;
};
中断说明:
compatible
属性匹配设备树节点。例如,VDMA驱动需与设备树中的compatible
字段一致。&vdma {
compatible = "xlnx,vdma-1.00.a";
reg = ;
status = "okay";
};
of匹配表
(如of_match_table
)声明支持的compatible
字符串。of_getproperty
读取设备树中的属性值(如寄存器地址、中断号)。# 编译dts为dtb
dtc -I dts -O dtb -o devicetree.dtb system.dts
# 反编译dtb为dts
dtc -I dtb -O dts -o decompiled.dts devicetree.dtb
# 创建Petalinux项目
petalinux-create --type project --name myproject --template zynq
# 进入项目目录
cd myproject
# 更新设备树
petalinux-config --get-hw-description=<path_to_xsa>
# 编译
petalinux-build
生成的设备树文件位于images/linux/
目录下。
# 从TFTP加载
tftp 0x1000000 devicetree.dtb
setenv fdtaddr 0x1000000
# 启动内核时指定设备树
bootm 0x3000000 - 0x1000000
# 查看当前设备树
cat /proc/device-tree/
# 查看特定节点
cat /proc/device-tree/amba/my_gpio/reg
对于动态配置,可以使用设备树覆盖:
# 加载覆盖
mkdir /config/device-tree/overlays
echo my_overlay.dtbo > /config/device-tree/overlays/load
假设我们在PL部分实现了一个PWM控制器,通过AXI-Lite总线连接到PS,基地址为0x43C00000,中断号为61(SPI 29)。
amba {
pwm: pwm@43c00000 {
compatible = "mycompany,pwm-controller";
reg = <0x43c00000 0x10000>;
interrupts = <0 29 4>;
interrupt-parent = <&intc>;
#pwm-cells = <2>;
clocks = <&clkc 15>;
clock-names = "pwm_clk";
status = "okay";
};
};
在驱动代码中,可以通过以下方式获取设备树信息:
static int pwm_probe(struct platform_device *pdev)
{
struct resource *res;
void __iomem *base;
int irq;
// 获取内存资源
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
// 获取中断
irq = platform_get_irq(pdev, 0);
// 获取时钟
struct clk *clk = devm_clk_get(&pdev->dev, "pwm_clk");
// 其他初始化...
}
错误示例:
Error: system.dts:10.1-9 syntax error
FATAL ERROR: Unable to parse input tree
解决方法:
dtc
的-v
选项获取更详细错误信息可能原因:
调试方法:
# 检查设备是否成功注册
ls /sys/bus/platform/devices/
# 查看内核日志
dmesg | grep your_device
症状:
Unable to handle kernel paging request at virtual address xxxxxxxx
解决方法:
status
是否为okay
。reg
地址与硬件设计是否一致。dtc
反编译.dtb
文件,对比修改前后的差异。dtc
检查语法:dtc -@ -I dts -O dtb -o test.dtb test.dts 2>&1
对于动态可重构系统,可以使用设备树覆盖:
// 覆盖片段
/dts-v1/;
/plugin/;
/ {
fragment@0 {
target = <&amba>;
__overlay__ {
new_device@43c10000 {
compatible = "xlnx,new-device";
reg = <0x43c10000 0x1000>;
};
};
};
};
当原始DTS丢失时:
dtc -I dtb -O dts -o recovered.dts system.dtb
可以在U-Boot中修改设备树:
# 查看设备树
fdt print /amba
# 修改节点
fdt set /amba/serial@e0001000 status "disabled"
Zynq设备树是连接硬件和软件的重要桥梁。通过本教程,您应该能够:
随着经验的积累,您将能够更高效地使用设备树来配置和管理Zynq系统的硬件资源。