2. 开发环境搭建:交叉编译工具链安装、SDK源码获取与编译、TFTP/NFS网络调试环境配置

做嵌入式Linux开发,环境搭建是第一道坎。很多人觉得这事简单,照着文档敲命令就行。但我见过太多人卡在这一步——工具链版本不对、SDK编译到一半报错、网络启动死活连不上。说白了,环境没搭好,后面调试全是空中楼阁。

这一章,我带你把Rockchip平台开发环境从头捋一遍。我会把个人习惯和踩过的坑都抖出来,你照着做,至少能省半天折腾时间。

2.1 交叉编译工具链安装

交叉编译,就是在PC上编译出能在ARM板子上跑的程序。Rockchip官方推荐用gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf这个版本。为什么?因为RK3399、RK3288这些芯片的Linux BSP都是基于这个工具链验证的。

核心原则:工具链版本必须与SDK匹配。不要自己随便下个最新版,否则链接时可能报一些莫名其妙的错误。

2.1.1 下载与解压

我个人习惯把工具链放在 /opt/toolchains/ 目录下,统一管理。

# 创建目录
sudo mkdir -p /opt/toolchains
cd /opt/toolchains

# 下载(如果网速慢,可以用百度网盘离线下载再传上来)
wget https://releases.linaro.org/components/toolchain/binaries/8.3-2019.03/arm-linux-gnueabihf/gcc-linaro-8.3.0-2019.03-x86_64_arm-linux-gnueabihf.tar.xz

# 解压
sudo tar -xvf gcc-linaro-8.3.0-2019.03-x86_64_arm-linux-gnueabihf.tar.xz -C /opt/toolchains/

2.1.2 配置环境变量

解压完别急着用。先配环境变量,否则系统找不到编译器。

# 编辑 ~/.bashrc 或 ~/.zshrc
vim ~/.bashrc

# 在文件末尾添加
export PATH=/opt/toolchains/gcc-linaro-8.3.0-2019.03-x86_64_arm-linux-gnueabihf/bin:$PATH
export CROSS_COMPILE=arm-linux-gnueabihf-
export ARCH=arm

# 使生效
source ~/.bashrc

小技巧:我习惯把 CROSS_COMPILE 和 ARCH 也写进环境变量。这样编译内核或uboot时,少敲几个参数。你想想看,每次都要手动指定,多烦。

2.1.3 验证安装

arm-linux-gnueabihf-gcc --version

如果能看到版本信息,说明工具链装好了。我曾经遇到一个情况——明明装了,但敲命令还是报"command not found"。后来发现是64位系统没装32位库。因为Linaro工具链是32位的,在64位Ubuntu上需要安装 lib32z1 lib32ncurses5 等库。

注意:Ubuntu 18.04及以上版本,还需要安装 libc6:i386。否则编译时会出现 /lib/ld-linux.so.2: bad ELF interpreter 错误。

2.2 SDK源码获取与编译

Rockchip的SDK通常通过repo管理。你从官方拿到的是manifest仓库,里面记录了所有子仓库的版本和地址。

2.2.1 获取SDK

以RK3399为例,官方SDK大概有10GB左右。建议用国内镜像,否则下载速度会让你怀疑人生。

# 安装repo工具
sudo apt-get install repo

# 初始化仓库
mkdir rk3399-sdk
cd rk3399-sdk
repo init -u https://github.com/rockchip-linux/manifests -b master

# 同步源码(这一步最耗时)
repo sync -j4

这里有个坑:repo sync 如果中途断了,重新执行就行。但有时候网络不稳定,某些仓库会一直失败。我遇到过这种情况,后来改用 repo sync -j1 单线程下载,虽然慢,但至少能跑完。

2.2.2 编译uboot

uboot是板子上电后第一个跑的程序。Rockchip的uboot编译比较简单,直接执行脚本就行。

cd u-boot
./make.sh rk3399

编译完成后,会在当前目录生成 uboot.img、trust.img、rk3399_loader_v1.12.112.bin 等文件。这些就是你要烧录到板子上的镜像。

经验之谈:我第一次编译uboot时,卡在 mkimage 命令找不到。后来发现是没装 u-boot-tools 包。执行 sudo apt-get install u-boot-tools 解决。

2.2.3 编译内核

内核编译比uboot复杂一些。需要先配置,再编译。

cd kernel
make ARCH=arm64 rockchip_linux_defconfig
make ARCH=arm64 rk3399-evb.img -j4

这里要注意:rk3399-evb.img 是官方EVB板的配置。如果你用的是自己画的板子,需要修改设备树文件。我一般会在 arch/arm64/boot/dts/rockchip/ 目录下新建一个 rk3399-myboard.dts,然后修改Makefile添加编译目标。

2.2.4 编译根文件系统

根文件系统可以用buildroot或yocto。对于初学者,我建议直接用Rockchip提供的 rootfs.img 预编译镜像。省事。

如果你想自己定制,可以这样:

cd buildroot
make rockchip_rk3399_defconfig
make -j4

编译完成后,在 output/images/ 目录下会生成 rootfs.ext4。这个文件可以直接烧录到板子的eMMC或SD卡上。

2.3 TFTP/NFS网络调试环境配置

嵌入式开发中,最常用的调试方式就是网络启动。板子通过TFTP下载内核和设备树,通过NFS挂载根文件系统。这样你修改代码后,只需要重新编译内核或应用,重启板子就能看到效果,不用反复烧录eMMC。

我画了一张图,帮你理解整个流程:

TFTP/NFS网络启动流程 PC主机(Ubuntu) TFTP服务器 + NFS服务器 Rockchip开发板 uboot → 内核 → 根文件系统 以太网 TFTP:传输内核/设备树 uboot加载内核到内存 NFS:共享根文件系统 内核挂载NFS根文件系统 为什么用TFTP+NFS? 修改代码 → 重新编译内核/应用 → 重启板子 → 自动加载新镜像 无需反复烧录eMMC,开发效率提升5倍以上

2.3.1 搭建TFTP服务器

TFTP服务器很简单,Ubuntu上装个 tftpd-hpa 就行。

sudo apt-get install tftpd-hpa

# 配置TFTP目录
sudo mkdir -p /tftpboot
sudo chmod 777 /tftpboot

# 编辑配置文件
sudo vim /etc/default/tftpd-hpa

配置文件内容如下:

TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/tftpboot"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="-l -c -s"

重启服务:

sudo systemctl restart tftpd-hpa

验证方法:在 /tftpboot 目录下放一个测试文件,然后在另一台机器上执行 tftp 192.168.1.100 -c get test.txt。如果能下载成功,说明TFTP服务器正常工作。

2.3.2 搭建NFS服务器

NFS用于共享根文件系统。板子启动后,内核会通过NFS挂载PC上的目录作为根文件系统。

sudo apt-get install nfs-kernel-server

# 创建共享目录(这里放你编译好的根文件系统)
sudo mkdir -p /srv/nfs/rootfs
sudo cp -a /path/to/your/rootfs/* /srv/nfs/rootfs/

# 配置导出
sudo vim /etc/exports

添加一行:

/srv/nfs/rootfs *(rw,sync,no_subtree_check,no_root_squash)

重启服务:

sudo exportfs -a
sudo systemctl restart nfs-kernel-server

注意:no_root_squash 这个参数很重要。如果不加,板子上的root用户会被映射成nobody,导致很多操作权限不足。我曾经因为这个参数,折腾了一下午才发现问题。

2.3.3 配置uboot网络启动参数

板子上电后,在uboot命令行中设置以下参数:

setenv ipaddr 192.168.1.10          # 板子IP
setenv serverip 192.168.1.100       # PC主机IP
setenv gatewayip 192.168.1.1        # 网关
setenv netmask 255.255.255.0        # 子网掩码

setenv bootargs root=/dev/nfs nfsroot=192.168.1.100:/srv/nfs/rootfs rw ip=192.168.1.10:192.168.1.100:192.168.1.1:255.255.255.0::eth0:off

setenv bootcmd 'tftp 0x02000000 rk3399-evb.dtb; tftp 0x00600000 Image; booti 0x00600000 - 0x02000000'

saveenv
boot

这里解释一下:

  • tftp 0x02000000 rk3399-evb.dtb:从TFTP服务器下载设备树到内存地址0x02000000
  • tftp 0x00600000 Image:下载内核镜像到0x00600000
  • booti 0x00600000 - 0x02000000:启动内核,设备树地址在0x02000000

避坑指南:内存地址不能乱写。RK3399的DRAM起始地址是0x00200000,内核通常加载到0x00600000,设备树加载到0x02000000。如果你用其他地址,可能会覆盖uboot自身或内核的解压缓冲区,导致启动失败。

2.4 环境验证清单

环境搭完了,怎么确认一切正常?我列了一个检查清单,你逐项过一遍:

检查项 验证方法 预期结果
交叉编译工具链 arm-linux-gnueabihf-gcc --version 显示版本号8.3.0
uboot编译 ./make.sh rk3399 生成uboot.img、trust.img
内核编译 make ARCH=arm64 rk3399-evb.img 生成Image和dtb文件
TFTP服务器 PC端 tftp localhost -c get test.txt 下载成功
NFS服务器 PC端 mount -t nfs localhost:/srv/nfs/rootfs /mnt 挂载成功,能看到文件
网络启动 板子uboot执行 boot 内核启动,挂载NFS根文件系统

到这步,你的开发环境就彻底搭好了。后面调试驱动、定位硬件问题,都可以在这个环境里快速迭代。记住,环境搭建是基础,基础打牢了,后面才能走得顺。