前言
本文翻译于Chiral Software的《Compiling Modules For The Jetson TX2》,点击阅读原文了解更多信息。
英伟达的Jetson TX2是在小型和低功耗设备上做机器学习方面应用开发的好东西。它的主机操作系统是标准的Ubuntu 16.04。这意味着我们可以启用任何我们需要的Linux内核模块,比如我们需要启用某些默认TX2不支持的网络设备。在我们的例子中,需要接入一个串行USB调制解调器,需要串行usb模块和其它一些模块。通过交叉编译模块,我们能够使用这些网络设备。
另一个选择是在Jetson本身上构建新的映像。这可以用来启用CDC ACM模块,这也是我们在这个过程中的目标。这样的脚本很容易使用,并且工作得很好。缺点是,在Jetson上编译比在桌面计算机上编译要慢而且不太方便。在这篇文章中,我们将展示从一个普通的桌面PC运行Ubuntu 16.04的具体步骤。
1
交叉编译
这已经在一个干净的安装上进行了测试,是没问题的。我已经提供了MD5s的文件来验证是否使用了正确的文件。
在普通PC上构建系统是ubuntu-16.04。
您将需要设置一些环境变量以使事情更容易。我创建了一个名为~/var .sh的文件:
export TEGRA_KERNEL_OUT=~/tegra/kernel export TEGRA_MODULES_OUT=~/tegra/modules export ARCH=arm64 export WORK=~/tegra-build export JETPACK=~/jetpack export DOWNLOADS=~/Downloads export CROSS_COMPILE=$WORK/install/bin/aarch64-unknown-linux-gnu- mkdir -p $TEGRA_KERNEL_OUT mkdir -p $TEGRA_MODULES_OUT
根据需要调整目录位置。运行此脚本建立变量: source ~/vars.sh
备注
export TEGRA_KERNEL_OUT=~/tegra/kernel export TEGRA_MODULES_OUT=~/tegra/modules
他在PC上建立了2个目录,用来存放编译出来的kernel和模块(例如一些驱动),这两行是两个环境变量. 后面用这2个变量的: mkdir -p $TEGRA_KERNEL_OUT mkdir -p $TEGRA_MODULES_OUT 等于打了mkdir -p ~/tegra/kernel
和打了mkdir -p ~/tegra/modules,
这样就建立了2个目录(注意变量被替换了)
2
下载
到NVIDIA官网:https://developer.nvidia.com/embedded/downloads 点击下载L4T Source。我们使用的是L4T 28.1 源文件。也可以打开open GCC Tool Chain for 64-bit BSP,下载文件GCC 4.8.5 Tool Chain for 64-bit BSP,把它们都放在$DOWNLOADS 目录下。
您会有:
b13f3e54a49483674ae2ef77dab1e0e5 source_release.tbz2 504b53528c2cd0e609dc2c5da6a7190c gcc-4.8.5-aarch64.tgz
建立一个工作目录,然后建压缩文件:
mkdir $WORK cd $WORK tar xf $DOWNLOADS/source_release.tbz2 tar xf $DOWNLOADS/gcc-4.8.5-aarch64.tgz cd sources tar xf kernel_src-tx2.tbz2
配置:
make -C kernel/kernel-4.4/ mrproper make -C kernel/kernel-4.4/ O=$TEGRA_KERNEL_OUT tegra18_defconfig make -C kernel/kernel-4.4/ O=$TEGRA_KERNEL_OUT menuconfig
备注
make -C kernel/kernel-4.4/ O=$TEGRA_KERNEL_OUT menuconfig ,
这里会出现一个菜单,用键盘上的光标键能选东西.这里得选需要的驱动.
这将在:$WORK/kernel/.config中创建内核配置文件。查看该文件,查看将使用的实际选项。构建命令使用CROSS_COMPILE的设置来使用针对ARM64的Nvidia的交叉编译器。
如果有警告说找不到courses.h,您可以使用apt安装libncurses5-dev。
在运行内核配置之前,您需要知道需要哪个模块。如果它是一个USB设备,一个简单的方法就是在Ubuntu上安装usbutils软件包,插入设备,并使用USB设备实用程序:
# usb-devices T: Bus=03 Lev=01 Prnt=01 Port=08 Cnt=04 Dev#= 15 Spd=12 MxCh= 0 D: Ver= 2.00 Cls=02(commc) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 P: Vendor=2a19 ProdID=0c00 Rev=01.00 S: Manufacturer=Numato Systems Pvt. Ltd. S: Product=Numato Lab 2 Channel USB Relay Module C: #Ifs= 2 Cfg#= 1 Atr=c0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 1 Cls=02(commc) Sub=02 Prot=01 Driver=cdc_acm I: If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=cdc_acm
这表明我们需要的模块是cdc_acm。
在menuconfig期间,您可以根据需要启用模块。menuconfig中的一个重要步骤是进入通用设置并定义一个本地版本。Nvidia的默认本地版本是-tegra。更改它,以明确这是一个独立的内核构建。如果使用本地版本,则必须与模块一起使用相同的本地版本。
3
建立模块
make -C kernel/kernel-4.4/ O=$TEGRA_KERNEL_OUT modules_prepare make -C kernel/kernel-4.4/ O=$TEGRA_KERNEL_OUT modules make -C kernel/kernel-4.4/ O=$TEGRA_KERNEL_OUT modules_install INSTALL_MOD_PATH=$TEGRA_MODULES_OUT
4
建立内核
如果您保持与默认内核相同的标记(-tegra),您应该能够通过将它们复制到/lib/modules并运行depmod来安装这些模块,从而避免reflashing。在这种情况下,你可以在这里结束。但是,我们将继续构建内核,设置文件系统,并flashing。
make -C kernel/kernel-4.4/ O=$TEGRA_KERNEL_OUT zImage make -C kernel/kernel-4.4/ O=$TEGRA_KERNEL_OUT dtbs
这些将编译内核映像。如果想要加快速度,可以使用-j4这样的选项并行运行make。在我的现代系统中,它在大约20分钟内编译了整个内核,没有并行编译。
备注
这里是说, 如果保留这上一步的-tegra的tag不变,生成的kernel模块文件可以直接复制到目标机器的对应目录,然后sudo depmod一下,这样其实可以不用编译kernel的. 然后这样你就可以本文终止了.
但是我们还是继续编译kernel(注意这里的kernel是Linux的kernel(内核), 不是CUDA C的kernel(核函数)),设好文件系统, 刷机(否则本文就太短了)。
make -C kernel/kernel-4.4/ O=$TEGRA_KERNEL_OUT zImage make -C kernel/kernel-4.4/ O=$TEGRA_KERNEL_OUT dtbs
注意编译kernel时候的变量使用,(之前你定义的$TEGRA_KERNEL_OUT)。
文中作者还说如果你的PC如果有4核,就-j4, 能加速,8核上-j8,16核上-j16,其实这个过程很快的。
5
用Jepack准备文件系统
你需要用JetPack来下rootfs(根分区或者叫根文件系统), 本文中是下载Jetpack3.1.
64ada3b06f3a5e664bd8ee92ca719172 JetPack-L4T-3.1-linux-x64.run
将 JetPack-L4T-3.1-linux-x64.放在 $JETPACK 下,然后运行:
mkdir $JETPACK cd $JETPACK cp $DOWNLOADS/JetPack-L4T-3.1-linux-x64.run . chmod ugo+rx JetPack-L4T-3.1-linux-x64.run ./JetPack-L4T-3.1-linux-x64.run
然后用Root运行JePack这个刷机软件, 里面选TX2,默认选了"全部"安装各种包,虽然这个很好, 但需要一些时间来下载,点击next开始下载过程。等下载和安装(到本地的对应的roofs目录下)所有的组件,JetPack将提示刷机过程, 询问你的TX2是怎么连接的。这里不要选继续,我们需要更新这个(本地)的rootfs和boot目录先,注意必须到了这个JetPack的生成(填充)好了rootfs的阶段, 你才能复制刚才编译得到的新kernel和模块们过去。Jetpack将会生成一个$JETPACK/64_TX2/Linux_for_Tegra_tx2的目录,在这个目录下面, 有一个flash.sh(刷机实用脚本),也包括一个叫kernel的目录, 用来生成启动ramdisk镜像,这个目录还包括一个rootfs目录, 里面是(最终用来刷给TX2)的根文件系统.
备注
这些就是说, 在刷给TX2之前, 需要从NV网站下载下来(自动的)并在本地PC上有了这些文件和目录,下一步就会将你改过(新编译出来的)kernel和modules目录复制过去
6
安装新的Kernel和模块
复制Kernel、Device Tree Blob (DTB)和模块:
sudo -s source ~/vars.sh cd $JETPACK/64_TX2/Linux_for_Tegra_tx2 cp $TEGRA_KERNEL_OUT/arch/arm64/boot/Image kernel cp $TEGRA_KERNEL_OUT/arch/arm64/boot/Image rootfs/boot cp -R $TEGRA_MODULES_OUT/lib/modules rootfs/lib/
现在,最终的得到的这个文件系统(目录)可以用来给TX2了,请注意, 之前的复制必须是root账号下进行,这是因为JetPack创建(这个系统目录里的)文件的时候,它是作为root权限运行的(你不是root权限改不掉之前的jetpack生成的这些文件的)。你可能继续再需要source一次vars.sh文件来设定变量 (就是从键盘输入source vars.sh回车,注意路径,来用你之前的那些设定过的变量)。
7
用JetPack刷机
本文作者推荐用的方式。点击JetPack界面里的"继续"(还记得你之前没有点继续嘛),来继续刷机过程。这个方法可以安装CUDA和其他后续安装的组件。
当然(作者认为)只能在界面上点来点去, 很烦人的,特别是当你要这样处理很多设备的时候,希望NV能弄一种方便的方式, 来缓存需要的这些软件包。JetPack刷机的时候每次给每个设备, 都需要重新下载一大堆包,所以刷机需要很长时间的.
8
刷机完成
刷机完成,会出现这样的提示:
[ 156.2511 ] Flashing completed [ 156.2512 ] Coldbooting the device [ 156.2520 ] tegradevflash_v2 --reboot coldboot [ 156.2526 ] Bootloader version 01.00.0000 [ 156.3605 ] *** The target t186ref has been flashed successfully. *** Reset the board to boot from internal eMMC.
如果你没看到这些文字(就是上面那些行), 肯定是哪里出错了,确定device处于recover模式,并且设备上电了, 并且整个刷机器件连接的良好。
连好网线,然后用ssh登录:
ssh 192.168.1.132 -l nvidia [email protected]'s password: Welcome to Ubuntu 16.04 LTS (GNU/Linux 4.4.38-chiral aarch64)
这说明TX2已经在运行定制过的kernel了,用root用户登录, 运行一次depmod(让你的系统能用上这些新编译的模块,然后重启。你的新模块就会看到,硬件开始工作!
9
DBT文件
关于Device Tree Binary,很多(教程里面)建议这样复制DTB文件:
cp $TEGRA_KERNEL_OUT/arch/arm64/boot/dts/*.dtb kernel/dtb cd $JETPACK/64_TX2/Linux_for_Tegra_tx2 ./apply_binaries.sh
作者尝试了这样做, 结果CUDA不能用了,CUDA只能在原始的DTB文件下工作。可能有一种重建DTB文件的方法, 同时不对CUDA造成干扰,但是本文作者没有提到。
10
总结
你应该已经完成好了这些步骤了:
这样你现在能很容易的使用那些能用来访问(驱动)你的设备的kernel模块了,登录到Tegra上, 看看我们的设备是否在那里:
ls /dev/ttyA* /dev/ttyACM0