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

做嵌入式Linux驱动开发,第一步就是把开发环境搭好。这一步要是没弄利索,后面调试起来会非常痛苦。我见过不少新手,花了一周时间在环境问题上打转,最后发现只是工具链版本不对。

这一章,我会把Rockchip平台开发环境的搭建过程拆开揉碎了讲。你跟着做就行,不用自己瞎琢磨。

2.1 交叉编译工具链安装

交叉编译,说白了就是在你的x86电脑上编译出能在ARM芯片上跑的程序。Rockchip官方推荐用Linaro提供的GCC工具链,我个人也一直用这个,稳定。

2.1.1 工具链版本选择

不同的Rockchip芯片,对应的工具链版本不太一样。我整理了一张表,你对着选就行。

芯片型号 架构 推荐工具链 GCC版本
RK3566/RK3568 ARMv8-A (64-bit) aarch64-linux-gnu 10.3-2021.07
RK3399 ARMv8-A (64-bit) aarch64-linux-gnu 9.2-2019.12
RK3288 ARMv7-A (32-bit) arm-linux-gnueabihf 8.3-2019.03
RV1126/RV1109 ARMv7-A (32-bit) arm-linux-gnueabihf 10.3-2021.07
注意: 我曾经遇到过用错工具链版本导致内核编译失败的情况。64位芯片必须用aarch64版本,32位芯片用arm版本,混用会报"unknown relocation"错误,排查起来很费时间。

2.1.2 安装步骤

以RK3568为例,我习惯把工具链放在 /opt/toolchains/ 目录下。

# 下载工具链
wget https://releases.linaro.org/components/toolchain/binaries/10.3-2021.07/aarch64-linux-gnu/gcc-linaro-10.3.1-2021.07-x86_64_aarch64-linux-gnu.tar.xz

# 解压到指定目录
sudo tar -xvf gcc-linaro-10.3.1-2021.07-x86_64_aarch64-linux-gnu.tar.xz -C /opt/toolchains/

# 添加环境变量
echo 'export PATH=$PATH:/opt/toolchains/gcc-linaro-10.3.1-2021.07-x86_64_aarch64-linux-gnu/bin' >> ~/.bashrc
source ~/.bashrc

# 验证安装
aarch64-linux-gnu-gcc --version
小技巧: 我建议你在 ~/.bashrc 里加上 export ARCH=arm64 和 export CROSS_COMPILE=aarch64-linux-gnu-。这样每次编译内核时就不用重复敲这两个参数了。

2.2 SDK源码获取与编译

Rockchip的SDK结构比较复杂,里面包含了U-Boot、Linux内核、Buildroot/ Yocto构建系统。我第一次接触时也懵了,后来摸清了门道就好办了。

2.2.1 获取SDK

Rockchip官方SDK托管在GitHub上,但完整源码需要从他们的repo仓库同步。我建议你用 repo 工具来管理,方便后续更新。

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

# 初始化SDK(以RK3568为例)
mkdir rk3568_sdk
cd rk3568_sdk
repo init -u https://github.com/rockchip-linux/manifests -b master -m rk3568_linux_release.xml

# 同步源码
repo sync -j4

同步时间取决于网络状况,我这边大概需要30-60分钟。你可以趁这个时间泡杯咖啡。

2.2.2 SDK目录结构

同步完成后,你会看到这样的目录结构:

rk3568_sdk/
├── u-boot/          # U-Boot引导程序
├── kernel/          # Linux内核源码
├── buildroot/       # Buildroot构建系统
├── device/          # 设备相关配置
├── external/        # 第三方库
├── prebuilts/       # 预编译工具
└── rockdev/         # 打包脚本和镜像

核心知识点: 驱动开发主要关注 kernel/ 目录下的 drivers/ 子目录。你的驱动代码就放在这里。U-Boot和Buildroot一般不需要频繁修改。

2.2.3 编译内核

编译内核是驱动开发的基本功。我习惯先编译一次完整的内核,确保环境没问题。

# 进入内核目录
cd kernel

# 配置内核(使用Rockchip默认配置)
make ARCH=arm64 rockchip_linux_defconfig

# 编译内核
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc)

# 编译设备树
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs

编译完成后,你会得到 arch/arm64/boot/Image 和 arch/arm64/boot/dts/rockchip/ 下的设备树文件。

注意: 编译时如果报 scripts/sign-file.c:25: fatal error: openssl/opensslv.h: No such file or directory 错误,安装 libssl-dev 即可解决。我刚开始时被这个坑过,折腾了半天。

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

驱动开发最烦的就是反复烧写镜像。用TFTP和NFS可以省去这个步骤,直接在网络加载内核和文件系统。我个人觉得这是嵌入式开发效率提升最大的一个技巧。

2.3.1 网络调试架构

先看一张整体架构图,理解数据是怎么流动的。

TFTP/NFS网络调试架构 开发主机 (x86) TFTP服务器 (tftp-hpa) NFS服务器 (nfs-kernel-server) 目标板 (RK3568) U-Boot → TFTP加载内核 内核 → NFS挂载根文件系统 TFTP传输 NFS挂载 工作流程说明 1. 目标板上电,U-Boot启动 2. U-Boot通过TFTP从开发主机下载内核镜像和设备树 3. 内核启动后,通过NFS挂载开发主机上的根文件系统 4. 驱动代码在开发主机上编译,目标板直接加载运行

2.3.2 TFTP服务器配置

TFTP用来传输内核镜像和设备树。配置很简单,几步搞定。

# 安装TFTP服务器
sudo apt-get install tftp-hpa

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

# 配置TFTP服务
sudo vim /etc/default/tftpd-hpa

配置文件内容如下:

TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/srv/tftp"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="--secure -c -s"
# 重启服务
sudo systemctl restart tftpd-hpa
sudo systemctl enable tftpd-hpa

然后把编译好的内核镜像和设备树复制到TFTP目录:

sudo cp arch/arm64/boot/Image /srv/tftp/
sudo cp arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dtb /srv/tftp/

2.3.3 NFS服务器配置

NFS用来挂载根文件系统。我一般用Buildroot生成的根文件系统,你也可以用Ubuntu base。

# 安装NFS服务器
sudo apt-get install nfs-kernel-server

# 创建NFS共享目录
sudo mkdir -p /srv/nfs/rootfs

# 解压根文件系统(以Buildroot为例)
sudo tar -xvf output/images/rootfs.tar -C /srv/nfs/rootfs/

# 配置NFS导出
sudo vim /etc/exports

在 /etc/exports 中添加:

/srv/nfs/rootfs *(rw,sync,no_subtree_check,no_root_squash)
# 重启NFS服务
sudo systemctl restart nfs-kernel-server
sudo exportfs -a
小技巧: no_root_squash 这个选项很重要。不加的话,目标板上的root用户会被映射成nobody,导致很多操作权限不足。我刚开始调试时,就因为这个问题折腾了一下午。

2.3.4 U-Boot启动参数设置

最后一步,配置U-Boot从TFTP和NFS启动。在目标板的U-Boot命令行中执行:

setenv serverip 192.168.1.100    # 开发主机IP
setenv ipaddr 192.168.1.10      # 目标板IP
setenv netmask 255.255.255.0
setenv gatewayip 192.168.1.1

setenv bootargs 'console=ttyS2,1500000 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 0x00a00000 Image; tftp 0x00f00000 rk3568-evb1-v10.dtb; booti 0x00a00000 - 0x00f00000'

saveenv
boot

执行 boot 后,你会看到内核通过TFTP加载,然后挂载NFS根文件系统。整个过程大概10-20秒,比烧写eMMC快多了。

效率提升: 用上TFTP/NFS后,每次修改驱动只需要重新编译内核模块,然后复制到NFS目录,重启目标板即可。整个过程不超过1分钟。相比之前每次烧写要5-10分钟,效率提升了5倍以上。

2.4 环境验证

环境搭好了,怎么确认没问题?我一般做三个检查:

  1. 工具链验证: 编译一个简单的hello world程序,用 file 命令确认是ARM架构。
  2. 内核编译验证: 确保 make 能完整编译通过,没有报错。
  3. 网络启动验证: 目标板能通过TFTP加载内核,NFS挂载根文件系统后能正常进入shell。

这三个检查都过了,你的开发环境就算搭建完成了。后面写驱动、调试,都会顺畅很多。