第三章:英伟达驱动开发环境配置
说实话,做嵌入式Linux下的英伟达驱动开发,环境配置这一步最容易被忽视。很多人一上来就想写代码,结果编译不过、跑不起来,最后发现是环境没搭对。我自己就吃过这个亏,所以今天咱们把这块彻底讲清楚。
3.1 L4T系统安装——从零开始
L4T,全称Linux for Tegra,是英伟达官方为Tegra系列SoC定制的Linux发行版。说白了,它就是你在Jetson设备上跑的那个操作系统。我个人习惯把L4T看作是「英伟达版的树莓派系统」,但底层驱动支持要完整得多。
安装L4T有两种方式:
- 刷写预编译镜像——适合快速上手
- 从源码构建——适合定制化需求
我建议初学者先用第一种方式。具体步骤其实不复杂:
- 从英伟达官网下载对应Jetson型号的L4T驱动包
- 准备一台Ubuntu主机(18.04或20.04都行)
- 把Jetson设备通过Micro-USB线连接到主机
- 让设备进入恢复模式(按住RECOVERY键再按RESET)
- 运行刷写脚本
核心命令示例:
# 进入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、设备树,这三样东西是英伟达驱动开发的基石。你想想看,如果连环境都没配好,后面写驱动、调性能根本无从谈起。所以,别嫌麻烦,一步步来,把基础打扎实了。
下一章咱们开始真正写驱动代码,到时候你会感谢今天认真搭环境的自己。