[实战]Zynq设备树详细教程

Zynq设备树详细教程(实际操作指南)

1. 设备树基础概念

1.1 什么是设备树

设备树(Device Tree)是一种描述硬件资源的数据结构,它通过一种树状结构来描述系统中的硬件设备信息。在Zynq系统中,设备树主要用来描述:

  • 处理器特性
  • 内存布局
  • 外设寄存器地址范围
  • 中断连接
  • 时钟信息
  • 其他硬件特定参数

1.2 设备树的作用

设备树(Device Tree)用于描述硬件配置信息,将硬件描述与驱动代码分离。通过.dts(设备树源文件)编译为.dtb(二进制设备树),供Linux内核在启动时解析硬件信息。

1.3设备树文件类型

  • DTS:设备树源文件,需手动编辑(如system-top.dts)。
  • DTSI:设备树头文件,类似C语言的.h文件,供DTS文件包含(如pl.dtsipcw.dtsi)。
  • DTB:编译后的二进制文件,由内核加载。
  • DTC:设备树编译器,用于编译.dts.dtb
  • DTG:Xilinx设备树生成工具,自动生成设备树文件。

1.4 关键节点与属性

  • compatible:驱动匹配的关键属性,格式为" manufacturer,device-type"
  • reg:描述硬件寄存器地址和大小。
  • status:设备状态(okaydisabled)。
  • #address-cells#size-cells:定义地址和大小的单元数。

2. Zynq设备树开发环境搭建

2.1 所需工具

  1. Xilinx SDK/Vitis - 包含设备树编译器(dtc)
  2. Petalinux工具 (可选) - 用于基于Linux的系统
  3. 文本编辑器 - 如VSCode、Vim等

2.2 设备树生成步骤

方法1:使用Vitis生成

  1. 导出XSA文件
    在Vivado中完成硬件设计后,导出.xsa文件(File → Export → Export hardware)。
  2. 生成设备树
    • 打开Vitis,创建新工程,选择File → New → Board Support Package
    • 选择设备树模板,配置BSP参数(如控制台端口、启动参数)。
    • 点击Apply and Close,生成设备树文件(system-top.dtspl.dtsipcw.dtsi等)。

方法2:使用SDK生成(传统方法)

  1. 配置设备树资源包
    • 下载设备树资源包(如device-tree-xlnx),解压到SDK安装目录(如/Xilinx/SDK/data embeddedsw)。
    • 在SDK中,通过Xilinx → repositories添加资源包路径。
  2. 创建BSP并生成设备树
    • 新建BSP时选择device_tree选项,配置启动参数(如console=ttyPS0,115200 root=/dev/mmcblk0p2)。
    • 生成设备树文件后,将其放入Petalinux工程的project-spec/meta-user/recipes-bsp/devicetree/files目录。

3. Zynq设备树结构解析

3.1 基本结构

一个典型的Zynq设备树文件结构如下:

/dts-v1/;

/ {
    #address-cells = <1>;
    #size-cells = <1>;
    compatible = "xlnx,zynq-7000";
    model = "Xilinx Zynq";
    
    cpus {
        /* CPU信息 */
    };
    
    memory {
        /* 内存信息 */
    };
    
    amba {
        /* 外设信息 */
    };
};

3.2 关键节点详解

3.2.1 CPU节点

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 = <&regulator_vccpint>;
        operating-points = <
            /* kHz    uV */
            666667  1000000
            333334  1000000
        >;
    };
};

3.2.2 内存节点

memory {
    device_type = "memory";
    reg = <0x0 0x40000000>;
};

3.2.3 AMBA总线节点

amba {
    compatible = "simple-bus";
    #address-cells = <1>;
    #size-cells = <1>;
    interrupt-parent = <&intc>;
    ranges;
    
    /* 外设定义在这里 */
};

3.3 设备树配置与修改

  1. 关键文件说明
    • system-top.dts:主设备树文件,包含所有硬件配置。
    • pl.dtsi:描述PL(可编程逻辑)端的外设。
    • pcw.dtsi:描述PS(处理系统)端的外设。
    • system-user.dtsi:用户自定义修改的优先级最高。
  2. 修改设备树
    • 启用外设:将status属性从disabled改为okay(如SD卡控制器)。
    • 添加自定义外设:在system-user.dtsi中添加节点,例如SPI控制器:
      &spiflash {
          compatible = "xlnx,spiflash";
          reg = ;
          status = "okay";
          #address-cells = ;
          #size-cells = ;
      };
      
    • 调整时钟与中断:配置clocksinterrupts属性,确保与硬件设计一致。
  3. 编译设备树
    • 使用dtc工具编译:
      dtc -I dts -O dtb -o output.dtb input.dts
      
    • 在Petalinux中,通过petalinux-config配置设备树路径,重新编译内核。

4. 为自定义硬件添加设备树节点

4.1 查找硬件地址信息

在Vivado中完成设计后:

  1. 导出硬件定义(XSA文件)
  2. 在"Address Editor"标签页查看外设基地址和范围

4.2 添加自定义IP节点示例

假设我们有一个自定义的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>;
    };
};

4.3 中断处理

Zynq中的中断定义:

intc: interrupt-controller@f8f01000 {
    compatible = "arm,gic-400", "arm,cortex-a9-gic";
    #interrupt-cells = <3>;
    interrupt-controller;
    reg = <0xF8F01000 0x1000>,
          <0xF8F00100 0x100>;
};

中断说明:

  • 第一个数字:中断类型(0=SPI, 1=PPI)
  • 第二个数字:中断号
  • 第三个数字:触发类型(1=上升沿, 4=高电平)

5 设备树与驱动绑定

  1. 驱动匹配规则
    • 驱动通过compatible属性匹配设备树节点。例如,VDMA驱动需与设备树中的compatible字段一致。
    • 示例:
      &vdma {
          compatible = "xlnx,vdma-1.00.a";
          reg = ;
          status = "okay";
      };
      
  2. 驱动代码适配
    • 在驱动代码中,通过of匹配表(如of_match_table)声明支持的compatible字符串。
    • 使用of_getproperty读取设备树中的属性值(如寄存器地址、中断号)。

6. 编译和部署设备树

6.1 手动编译设备树

# 编译dts为dtb
dtc -I dts -O dtb -o devicetree.dtb system.dts

# 反编译dtb为dts
dtc -I dtb -O dts -o decompiled.dts devicetree.dtb

6.2 使用Petalinux工具

# 创建Petalinux项目
petalinux-create --type project --name myproject --template zynq

# 进入项目目录
cd myproject

# 更新设备树
petalinux-config --get-hw-description=<path_to_xsa>

# 编译
petalinux-build

生成的设备树文件位于images/linux/目录下。

5.3 在U-Boot中加载设备树

# 从TFTP加载
tftp 0x1000000 devicetree.dtb
setenv fdtaddr 0x1000000

# 启动内核时指定设备树
bootm 0x3000000 - 0x1000000

7. 调试设备树

7.1 查看系统设备树

# 查看当前设备树
cat /proc/device-tree/

# 查看特定节点
cat /proc/device-tree/amba/my_gpio/reg

7.2 设备树覆盖

对于动态配置,可以使用设备树覆盖:

# 加载覆盖
mkdir /config/device-tree/overlays
echo my_overlay.dtbo > /config/device-tree/overlays/load

8. 实际案例:为Zynq添加自定义外设

8.1 案例描述

假设我们在PL部分实现了一个PWM控制器,通过AXI-Lite总线连接到PS,基地址为0x43C00000,中断号为61(SPI 29)。

8.2 设备树节点

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";
    };
};

8.3 驱动中使用设备树

在驱动代码中,可以通过以下方式获取设备树信息:

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");
    
    // 其他初始化...
}

9. 常见问题解决

9.1 设备树语法错误

错误示例

Error: system.dts:10.1-9 syntax error
FATAL ERROR: Unable to parse input tree

解决方法

  • 检查括号是否匹配
  • 检查分号是否遗漏
  • 使用dtc-v选项获取更详细错误信息

9.2 外设无法识别

可能原因

  • 寄存器地址不正确
  • 中断号或中断父节点错误
  • compatible字符串不匹配

调试方法

# 检查设备是否成功注册
ls /sys/bus/platform/devices/

# 查看内核日志
dmesg | grep your_device

9.3 内存映射错误

症状

Unable to handle kernel paging request at virtual address xxxxxxxx

解决方法

  • 检查设备树中的reg属性是否正确
  • 确保地址范围不与其他设备重叠

9.4 启动失败或设备未识别

  • 检查设备树中status是否为okay
  • 验证reg地址与硬件设计是否一致。
  • 使用dtc反编译.dtb文件,对比修改前后的差异。

9.5 设备树语法错误

  • 使用dtc检查语法:
    dtc -@ -I dts -O dtb -o test.dtb test.dts 2>&1
    
  • 确保括号、引号和逗号闭合正确。

10. 最佳实践

  1. 模块化设计:将通用部分放在.dtsi文件中,板级特定配置放在.dts中
  2. 版本控制:将设备树文件纳入版本控制系统
  3. 注释:为每个节点添加详细注释
  4. 验证:在修改前后都进行完整系统测试
  5. 备份:保留工作版本的设备树文件

11. 进阶主题

11.1 设备树覆盖(DTO)

对于动态可重构系统,可以使用设备树覆盖:

// 覆盖片段
/dts-v1/;
/plugin/;

/ {
    fragment@0 {
        target = <&amba>;
        
        __overlay__ {
            new_device@43c10000 {
                compatible = "xlnx,new-device";
                reg = <0x43c10000 0x1000>;
            };
        };
    };
};

11.2 使用DTB反推DTS

当原始DTS丢失时:

dtc -I dtb -O dts -o recovered.dts system.dtb

11.3 设备树与U-Boot

可以在U-Boot中修改设备树:

# 查看设备树
fdt print /amba

# 修改节点
fdt set /amba/serial@e0001000 status "disabled"

结论

Zynq设备树是连接硬件和软件的重要桥梁。通过本教程,您应该能够:

  1. 理解设备树的基本结构和语法
  2. 为自定义硬件添加设备树节点
  3. 编译和部署设备树
  4. 调试设备树相关问题
  5. 应用最佳实践进行设备树开发

随着经验的积累,您将能够更高效地使用设备树来配置和管理Zynq系统的硬件资源。


附录:工具与资源

  • 设备树生成工具:DTG(Xilinx官方工具)、Petalinux设备树生成器。
  • 编译工具:DTC(设备树编译器)、dtc(反编译工具)。
  • 参考文档:
    • Xilinx设备树生成指南:链接
    • Petalinux设备树配置手册:链接
      通过以上步骤,开发者可以高效完成Zynq设备树的生成、配置与调试,实现硬件与驱动的无缝对接。

猜你喜欢

转载自blog.csdn.net/jz_ddk/article/details/146920043
今日推荐