第二章 开发环境搭建:工欲善其事,必先利其器

做嵌入式开发,尤其是RK平台这种级别的SoC,环境搭建是第一道坎。很多人觉得不就是装个编译器、下个代码嘛,结果一上手就卡在莫名其妙的地方。我见过太多人花了两三天才把网络环境调通,最后发现是网线没插好——嗯,真事。

这一章,我把环境搭建的流程拆成三块:交叉编译工具链、源码获取、网络调试环境。每块都有我踩过的坑,你跟着走一遍,基本不会出大问题。

2.1 交叉编译工具链配置

交叉编译,说白了就是在你的x86电脑上编译出ARM能跑的二进制。RK平台官方推荐用gcc-arm-8.3-2019.03,但我个人习惯用Linaro的版本,更新快,社区支持好。

核心原则:工具链版本必须与内核版本匹配。RK3288用4.4内核时,gcc 6.x就够了;RK3588用5.10内核,建议gcc 8.x以上。

2.1.1 下载与安装

# 下载Linaro gcc 7.5(适用于RK3399/RK3288)
wget https://releases.linaro.org/components/toolchain/binaries/7.5-2019.12/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz

# 解压到/opt目录
sudo tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -C /opt/

# 配置环境变量(建议写入~/.bashrc)
export PATH=/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin:$PATH
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-

小技巧:我习惯在项目根目录下放一个 setenv.sh 脚本,每次开新终端直接 source setenv.sh,省得反复写环境变量。

2.1.2 验证工具链

# 检查版本
arm-linux-gnueabihf-gcc --version

# 编译一个测试程序
echo 'int main(){return 0;}' > test.c
arm-linux-gnueabihf-gcc -o test test.c
file test
# 输出应为:ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV)

如果 file 命令显示的是x86格式,说明你还在用本地gcc。我曾经有个同事搞了一整天,最后发现 CROSS_COMPILE 变量名拼错了——少了个字母。

注意:RK平台有32位和64位之分。RK3288是ARMv7,用 arm-linux-gnueabihf-;RK3399/RK3588是ARMv8,用 aarch64-linux-gnu-。别搞混了,否则编译出来的内核起不来。

2.2 Uboot与内核源码获取

源码获取这件事,看似简单,但版本选错了后面全是坑。RK官方在GitHub上有完整的仓库,但分支多、tag乱,新手容易迷失。

2.2.1 官方仓库地址

组件 GitHub仓库 推荐分支
U-Boot rockchip-linux/u-boot next-dev(开发板)或 2017.09(稳定)
Kernel rockchip-linux/kernel rk-5.10(RK3588)或 rk-4.4(RK3288)
RKBin rockchip-linux/rkbin master

2.2.2 克隆与切换分支

# 克隆内核(以RK3588为例)
git clone https://github.com/rockchip-linux/kernel.git -b rk-5.10 --depth=1

# 克隆U-Boot
git clone https://github.com/rockchip-linux/u-boot.git -b next-dev --depth=1

# 克隆rkbin(包含DDR初始化、ATF等二进制)
git clone https://github.com/rockchip-linux/rkbin.git --depth=1

--depth=1 只拉最新代码,省时间省硬盘。我刚开始做RK3588时没加这个参数,拉了3个多G,结果发现大部分历史commit根本用不上。

我的习惯:在 /work/rk3588/ 下建三个目录:src/(放源码)、out/(放编译产物)、tools/(放烧录工具和脚本)。这样项目结构清晰,不会乱。

2.3 TFTP/NFS网络调试环境搭建

网络调试是嵌入式开发的加速器。没有它,每次改代码都要插拔SD卡或USB线,效率极低。TFTP用来传内核和设备树,NFS用来挂载根文件系统——这两个配合好,开发体验直接起飞。

2.3.1 整体架构

先看一张图,理清数据流:

TFTP/NFS网络调试架构图 TFTP/NFS 网络调试架构 开发主机 (x86) TFTP Server (tftp-hpa) NFS Server (nfs-kernel-server) IP: 192.168.1.100 存放: zImage, dtb, rootfs 目标板 (RK3588) U-Boot 启动 TFTP 获取内核/DTB NFS 挂载根文件系统 IP: 192.168.1.101 以太网交换机 或 直连网线 数据流说明 ① 目标板上电 → U-Boot 初始化网络 → ② TFTP 获取 zImage + dtb ③ 内核启动 → ④ NFS 挂载根文件系统 → ⑤ 进入系统,开始调试

2.3.2 搭建TFTP服务器

# 安装tftp-hpa
sudo apt-get install tftp-hpa tftpd-hpa

# 创建TFTP根目录
sudo mkdir -p /tftpboot
sudo chmod 777 /tftpboot

# 修改配置文件 /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
sudo systemctl enable tftpd-hpa

验证方法:在 /tftpboot 下放一个测试文件,然后在另一台机器上执行 tftp 192.168.1.100 -c get test.txt。能下载就说明通了。

2.3.3 搭建NFS服务器

# 安装nfs-kernel-server
sudo apt-get install nfs-kernel-server

# 创建NFS共享目录(存放根文件系统)
sudo mkdir -p /srv/nfs/rootfs
sudo chmod 777 /srv/nfs/rootfs

# 解压根文件系统到共享目录
sudo tar -xvf buildroot-rootfs.tar.gz -C /srv/nfs/rootfs/

# 编辑 /etc/exports,添加共享配置
/srv/nfs/rootfs 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)

# 重启NFS服务
sudo systemctl restart nfs-kernel-server
sudo exportfs -av

关键点:no_root_squash 必须加。不加的话,目标板上的root用户会被映射成nobody,很多操作会报权限错误。我曾经因为这个排查了整整一个下午,最后发现是少了个参数。

2.3.4 U-Boot端网络启动配置

在U-Boot命令行中设置环境变量:

# 设置IP地址
setenv ipaddr 192.168.1.101
setenv serverip 192.168.1.100
setenv gatewayip 192.168.1.1
setenv netmask 255.255.255.0

# 设置TFTP启动参数
setenv bootcmd 'tftp 0x02000000 zImage; tftp 0x06000000 rk3588-evb1.dtb; bootz 0x02000000 - 0x06000000'

# 设置NFS根文件系统参数
setenv bootargs 'console=ttyS2,1500000 root=/dev/nfs nfsroot=192.168.1.100:/srv/nfs/rootfs,v3,tcp ip=192.168.1.101:192.168.1.100:192.168.1.1:255.255.255.0::eth0:off'

# 保存环境变量
saveenv

# 启动
boot

这里有个坑:bootz 命令只支持ARM32内核。如果你用的是RK3588这种64位平台,得用 booti。我刚开始移植时没注意这个,内核死活起不来,打印停在"Starting kernel ..."就不动了。

2.3.5 常见故障排查

现象 可能原因 解决方法
TFTP超时 防火墙阻挡或网线问题 sudo ufw disable 或检查网线
NFS挂载失败 缺少 no_root_squash 检查 /etc/exports 配置
内核启动后卡住 DTB与内核版本不匹配 确保DTB来自同一份内核源码
网络不通 PHY驱动未初始化 U-Boot中执行 mdio list 检查PHY

我的经验:网络调试环境第一次搭好之后,把U-Boot的环境变量导出保存到文件。下次换板子或重刷固件时,直接 source 进去,省得重新敲一遍。我曾经有个项目换了三块不同版本的RK3588板子,每次都要重新配IP,后来学乖了,写了个脚本一键配置。

2.4 本章小结

环境搭建这件事,说难不难,说简单也不简单。工具链版本选对、源码分支选对、网络服务配好,后面30章的实战才能跑得起来。如果你按照上面的步骤走一遍,应该半小时内就能搭好。