第三章:英伟达驱动开发环境配置

说实话,做嵌入式Linux下的英伟达驱动开发,环境配置这一步最容易被忽视。很多人一上来就想写代码,结果编译不过、跑不起来,最后发现是环境没搭对。我自己就吃过这个亏,所以今天咱们把这块彻底讲清楚。

3.1 L4T系统安装——从零开始

L4T,全称Linux for Tegra,是英伟达官方为Tegra系列SoC定制的Linux发行版。说白了,它就是你在Jetson设备上跑的那个操作系统。我个人习惯把L4T看作是「英伟达版的树莓派系统」,但底层驱动支持要完整得多。

安装L4T有两种方式:

  • 刷写预编译镜像——适合快速上手
  • 从源码构建——适合定制化需求

我建议初学者先用第一种方式。具体步骤其实不复杂:

  1. 从英伟达官网下载对应Jetson型号的L4T驱动包
  2. 准备一台Ubuntu主机(18.04或20.04都行)
  3. 把Jetson设备通过Micro-USB线连接到主机
  4. 让设备进入恢复模式(按住RECOVERY键再按RESET)
  5. 运行刷写脚本

核心命令示例:

# 进入L4T驱动包目录
cd ~/L4T/Linux_for_Tegra/

# 刷写系统到Jetson设备
sudo ./flash.sh jetson-xavier-nx-devkit mmcblk0p1

注意:刷写过程中千万不要断开USB连接。我曾经有一次手贱拔了线,结果设备变砖,折腾了一整天才救回来。

3.2 JetPack SDK安装与配置

JetPack SDK是英伟达提供的一整套开发工具包。它包含了L4T系统、CUDA、cuDNN、TensorRT、多媒体API等等。你想想看,如果没有JetPack,你得一个个去装这些依赖,光是版本匹配就能让你崩溃。

安装JetPack有两种方式:

  • SDK Manager图形界面——推荐新手使用
  • 命令行安装——适合自动化部署

我个人更倾向于命令行方式,因为可以写脚本一键部署。但如果你是第一次接触,用SDK Manager会更直观。

我的经验:安装JetPack时,记得勾选「Host Machine」和「Target Machine」两个选项。前者会在你的Ubuntu主机上安装交叉编译工具链,后者会直接刷写到Jetson设备上。我刚开始就只选了Target,结果在主机上编译时找不到头文件,折腾了半天才发现问题。

安装完成后,验证一下环境是否正常:

# 检查CUDA版本
nvcc --version

# 检查cuDNN版本
cat /usr/include/cudnn_version.h | grep CUDNN_MAJOR -A 2

# 检查TensorRT版本
dpkg -l | grep tensorrt

3.3 设备树(Device Tree)基础与编译

设备树,英文叫Device Tree,是嵌入式Linux里用来描述硬件信息的一种数据结构。说白了,它就是告诉内核:「我这块板子上有哪些外设,它们挂在哪条总线上,中断号是多少,寄存器地址在哪。」

为什么需要设备树?因为ARM架构不像x86那样有ACPI自动枚举硬件。每个嵌入式板子的硬件配置都不一样,总不能为每块板子都重新编译内核吧?设备树就是为了解决这个问题——硬件描述和内核代码分离。

设备树的文件格式有两种:

  • .dts——设备树源文件,人类可读的文本格式
  • .dtb——设备树二进制文件,内核实际加载的格式

编译过程很简单:

# 将dts编译成dtb
dtc -I dts -O dtb -o my_device.dtb my_device.dts

# 反编译dtb查看内容
dtc -I dtb -O dts -o my_device.dts my_device.dtb

一个简单的设备树示例:

/dts-v1/;

/ {
    compatible = "nvidia,tegra194";
    
    cpu@0 {
        compatible = "arm,cortex-a76";
        reg = <0x0>;
    };
    
    serial@3100000 {
        compatible = "nvidia,tegra194-uart";
        reg = <0x3100000 0x10000>;
        interrupts = <0 112 4>;
        status = "okay";
    };
};

这里要注意几个关键点:

  • compatible属性用于匹配驱动,内核通过它找到对应的驱动程序
  • reg描述寄存器地址和大小
  • interrupts指定中断号、触发类型
  • status可以设为"okay"或"disabled"来控制设备是否启用

避坑指南:我曾经在修改设备树时,把reg的地址写错了,结果驱动加载时一直报错「无法映射寄存器」。查了两天才发现是地址偏移了一位。所以,写设备树时一定要对照芯片手册,一个字都不能错。

在Jetson平台上,设备树文件通常放在这里:

/boot/dtb/
├── tegra194-p2888-0001-p2822-0000.dtb
├── tegra194-p2888-0004-p2822-0000.dtb
└── ...

如果你想修改设备树,建议先备份原文件:

sudo cp /boot/dtb/tegra194-p2888-0001-p2822-0000.dtb \
        /boot/dtb/tegra194-p2888-0001-p2822-0000.dtb.backup

3.4 实战:为Jetson添加一个SPI设备

光说不练假把式。咱们来一个实际案例——在Jetson Xavier NX上添加一个SPI设备。

首先,找到Jetson的设备树源文件。英伟达通常不直接提供dts,而是提供dtsi(包含文件)。你需要从dtb反编译得到dts:

dtc -I dtb -O dts -o tegra194.dts /boot/dtb/tegra194-p2888-0001-p2822-0000.dtb

然后,在dts中找到SPI控制器节点,添加你的设备:

&spi@3210000 {
    status = "okay";
    
    my_spi_device@0 {
        compatible = "mycompany,my-spi-device";
        reg = <0x0>;  // 片选线0
        spi-max-frequency = <10000000>;  // 10MHz
    };
};

编译并替换dtb:

dtc -I dts -O dtb -o my.dtb tegra194.dts
sudo cp my.dtb /boot/dtb/tegra194-p2888-0001-p2822-0000.dtb
sudo reboot

小技巧:修改设备树后,可以用这个命令检查内核是否成功加载了你的设备:

dmesg | grep my_spi_device

如果看到「registered new device」之类的信息,说明设备树生效了。

嗯,到这里环境配置这块就差不多了。L4T系统、JetPack SDK、设备树,这三样东西是英伟达驱动开发的基石。你想想看,如果连环境都没配好,后面写驱动、调性能根本无从谈起。所以,别嫌麻烦,一步步来,把基础打扎实了。

下一章咱们开始真正写驱动代码,到时候你会感谢今天认真搭环境的自己。